Selaa lähdekoodia

1、所有飞控端所需的硬件驱动均以配置并测试完毕

zhuts 1 viikko sitten
vanhempi
sitoutus
1ab38a43cb
31 muutettua tiedostoa jossa 2009 lisäystä ja 706 poistoa
  1. 23 22
      controller_yy_app/hardware/hard_can.c
  2. 0 1
      controller_yy_app/hardware/hard_inc/hard_can.h
  3. 0 1
      controller_yy_app/hardware/hard_inc/hard_flash_gd25q16.h
  4. 0 2
      controller_yy_app/hardware/hard_inc/hard_imu_uart3.h
  5. 0 1
      controller_yy_app/hardware/hard_inc/hard_rc_sbus.h
  6. 1 1
      controller_yy_app/hardware/hard_inc/hard_system.h
  7. 0 1
      controller_yy_app/hardware/hard_inc/hard_system_delay.h
  8. 0 1
      controller_yy_app/hardware/hard_inc/hard_system_timer.h
  9. 0 188
      controller_yy_app/hardware/hard_sdio_sd.c
  10. 2 2
      controller_yy_app/hardware/hard_system.c
  11. 2 0
      controller_yy_app/software/debug_printf.c
  12. 3 1
      controller_yy_app/software/soft_can.c
  13. 599 0
      controller_yy_app/software/soft_flash.c
  14. 0 1
      controller_yy_app/software/soft_inc/soft_sdcard.h
  15. 1 0
      controller_yy_app/software/soft_inc/soft_time.h
  16. 614 1
      controller_yy_app/software/soft_motor_output.c
  17. 1 1
      controller_yy_app/software/soft_port_uart4.c
  18. 4 3
      controller_yy_app/software/soft_sdcard.c
  19. 157 1
      controller_yy_app/software/soft_system.c
  20. 194 0
      controller_yy_app/software/soft_time.c
  21. 45 8
      controller_yy_app/software/soft_voltage.c
  22. 32 4
      controller_yy_app/user_src/inc/test.h
  23. 14 312
      controller_yy_app/user_src/main.c
  24. 259 76
      controller_yy_app/v8/v8m/bsp_V8M_flash.c
  25. 1 0
      controller_yy_app/v8/v8m/bsp_V8M_flash.h
  26. 26 22
      controller_yy_app/v8/v8m_yy/bsp_V8M_YY_adc.c
  27. 0 2
      controller_yy_app/v8/v8m_yy/bsp_V8M_YY_adc.h
  28. 0 4
      controller_yy_app/v8/v8m_yy/bsp_V8M_YY_led.h
  29. 0 1
      controller_yy_app/v8/v8m_yy/bsp_V8M_YY_pwm.h
  30. 26 48
      controller_yy_app_controller_yy_board_flash_sdram_xip_debug/segger_embedded_studio/controlware_yy_app.emSession
  31. 5 1
      踩坑.md

+ 23 - 22
controller_yy_app/hardware/hard_can.c

@@ -81,29 +81,30 @@ static volatile  bool has_error;
 static volatile  can_receive_buf_t s_can_rx_buf;
 static volatile  uint8_t error_flags;
 // 中断函数在soft can 那里
-//SDK_DECLARE_EXT_ISR_M(CAN2_IRQ, can2_isr)
-//void can2_isr(void)
-//{
-//    uint8_t flags = can_get_tx_rx_flags(CAN2);
-//    if ((flags & CAN_EVENT_RECEIVE) != 0) {
-//        can_read_received_message(CAN2, (can_receive_buf_t *)&s_can_rx_buf);
-//        has_new_rcv_msg = true;
-//    }
-//    if ((flags & (CAN_EVENT_TX_PRIMARY_BUF | CAN_EVENT_TX_SECONDARY_BUF))) {
-//        has_sent_out = true;
-//    }
-//    if ((flags & CAN_EVENT_ERROR) != 0) {
-//        has_error = true;
-//    }
-//    can_clear_tx_rx_flags(CAN2, flags);
-
-//    error_flags = can_get_error_interrupt_flags(CAN2);
-//    if (error_flags != 0) {
-//        has_error = true;
-//    }
-//    can_clear_error_interrupt_flags(CAN2, error_flags);
-//}
+#ifdef TEST_EN
+SDK_DECLARE_EXT_ISR_M(CAN2_IRQ, can2_isr)
+void can2_isr(void)
+{
+    uint8_t flags = can_get_tx_rx_flags(CAN2);
+    if ((flags & CAN_EVENT_RECEIVE) != 0) {
+        can_read_received_message(CAN2, (can_receive_buf_t *)&s_can_rx_buf);
+        has_new_rcv_msg = true;
+    }
+    if ((flags & (CAN_EVENT_TX_PRIMARY_BUF | CAN_EVENT_TX_SECONDARY_BUF))) {
+        has_sent_out = true;
+    }
+    if ((flags & CAN_EVENT_ERROR) != 0) {
+        has_error = true;
+    }
+    can_clear_tx_rx_flags(CAN2, flags);
 
+    error_flags = can_get_error_interrupt_flags(CAN2);
+    if (error_flags != 0) {
+        has_error = true;
+    }
+    can_clear_error_interrupt_flags(CAN2, error_flags);
+}
+#endif
 static uint8_t can_get_data_bytes_from_dlc(uint32_t dlc)
 {
     uint32_t data_bytes = 0;

+ 0 - 1
controller_yy_app/hardware/hard_inc/hard_can.h

@@ -5,6 +5,5 @@
 
 void CAN1_Mode_Init(uint32_t baudrate);
 
-void can2_test(void);
 
 #endif // ! HARD_CAN_H

+ 0 - 1
controller_yy_app/hardware/hard_inc/hard_flash_gd25q16.h

@@ -72,5 +72,4 @@ void gd25q16_cs_high(void);
 
 void gd25q16_cs_low(void);
 
-void test_gd25q16_quick(void);
 #endif

+ 0 - 2
controller_yy_app/hardware/hard_inc/hard_imu_uart3.h

@@ -23,6 +23,4 @@ bool usart3_tx_isbusy(void);
 
 void control_board_led_on(void);
 
-void imu_uart3_test(void);
-
 #endif

+ 0 - 1
controller_yy_app/hardware/hard_inc/hard_rc_sbus.h

@@ -12,5 +12,4 @@ extern unsigned char uart2_dma_rx_buf[UART2_RX_LENDTH_MAX]; // 实际是串口
 
 extern void rc_sbus_init(uint32_t baud);
 // 由于hpm6750没有串口空闲中断, 所以采用串口超时中断的而形式 FIFO深度16字节
-extern void uart2_sbus_test(void);
 #endif

+ 1 - 1
controller_yy_app/hardware/hard_inc/hard_system.h

@@ -6,6 +6,6 @@ void sys_reset(void);
 
 void u3_dma_disable(void);
 
-void system_test(void);
+
 #endif
 

+ 0 - 1
controller_yy_app/hardware/hard_inc/hard_system_delay.h

@@ -5,7 +5,6 @@
 void system_delay_init(uint8_t SYSCLK);
 void system_delay_ms(uint32_t nms);
 void system_delay_us(uint32_t nus);
-void cpu_delay_test(void);
 
 #endif
 

+ 0 - 1
controller_yy_app/hardware/hard_inc/hard_system_timer.h

@@ -3,7 +3,6 @@
 
 
 void system_timer_init(void);
-void timer1_test(void);
 
 #endif
 

+ 0 - 188
controller_yy_app/hardware/hard_sdio_sd.c

@@ -8,192 +8,4 @@
 
 // SD_TEST 20260322 pass 
 #ifdef SD_TEST
-#include "hpm_sdmmc_sd.h"
-#include "ff.h"
-#include "diskio.h"
-
-FATFS s_sd_disk;
-FIL s_file;
-DIR s_dir;
-FRESULT fatfs_result;
-BYTE work[FF_MAX_SS];
-const TCHAR driver_num_buf[4] = { DEV_SD + '0', ':', '/', '\0' };
-
-#define TEST_DIR_NAME "hpmicro_sd_test_dir0"
-
-static FRESULT sd_write_file(void)
-{
-    FRESULT fresult = f_open(&s_file, "readme.txt", FA_WRITE | FA_CREATE_ALWAYS);
-    if (fresult != FR_OK) {
-        printf("Create new file failed, cause: %d\n", show_error_string(fresult));
-    } else {
-        printf("Create new file successfully, status=%d\n", fresult);
-    }
-    char hello_str[] = "Hello, this is SD card FATFS demo\n";
-    UINT byte_written;
-    fresult = f_write(&s_file, hello_str, sizeof(hello_str), &byte_written);
-    if (fresult != FR_OK) {
-        printf("Write file failed, cause: %s\n", show_error_string(fresult));
-    } else {
-        printf("Write file operation is successfully\n");
-    }
-
-    f_close(&s_file);
-
-    return fresult;
-}
-
-static FRESULT sd_read_file(void)
-{
-    FRESULT fresult = f_open(&s_file, "readme.txt", FA_READ);
-    if (fresult != FR_OK) {
-        printf("Open file failed, cause: %s\n", show_error_string(fresult));
-    } else {
-        printf("Open file successfully\n");
-    }
-
-    if (fresult != FR_OK) {
-        return fresult;
-    }
-
-    TCHAR str[100];
-    f_gets(str, sizeof(str), &s_file);
-    printf("%s\n", str);
-
-    f_close(&s_file);
-
-    return fresult;
-}
-const char *show_error_string(FRESULT fresult)
-{
-    const char *result_str;
-
-    switch (fresult) {
-    case FR_OK:
-        result_str = "succeeded";
-        break;
-    case FR_DISK_ERR:
-        result_str = "A hard error occurred in the low level disk I/O level";
-        break;
-    case FR_INT_ERR:
-        result_str = "Assertion failed";
-        break;
-    case FR_NOT_READY:
-        result_str = "The physical drive cannot work";
-        break;
-    case FR_NO_FILE:
-        result_str = "Could not find the file";
-        break;
-    case FR_NO_PATH:
-        result_str = "Could not find the path";
-        break;
-    case FR_INVALID_NAME:
-        result_str = "Tha path name format is invalid";
-        break;
-    case FR_DENIED:
-        result_str = "Access denied due to prohibited access or directory full";
-        break;
-    case FR_EXIST:
-        result_str = "Access denied due to prohibited access";
-        break;
-    case FR_INVALID_OBJECT:
-        result_str = "The file/directory object is invalid";
-        break;
-    case FR_WRITE_PROTECTED:
-        result_str = "The physical drive is write protected";
-        break;
-    case FR_INVALID_DRIVE:
-        result_str = "The logical driver number is invalid";
-        break;
-    case FR_NOT_ENABLED:
-        result_str = "The volume has no work area";
-        break;
-    case FR_NO_FILESYSTEM:
-        result_str = "There is no valid FAT volume";
-        break;
-    case FR_MKFS_ABORTED:
-        result_str = "THe f_mkfs() aborted due to any problem";
-        break;
-    case FR_TIMEOUT:
-        result_str = "Could not get a grant to access the volume within defined period";
-        break;
-    case FR_LOCKED:
-        result_str = "The operation is rejected according to the file sharing policy";
-        break;
-    case FR_NOT_ENOUGH_CORE:
-        result_str = "LFN working buffer could not be allocated";
-        break;
-    case FR_TOO_MANY_OPEN_FILES:
-        result_str = "Number of open files > FF_FS_LOCK";
-        break;
-    case FR_INVALID_PARAMETER:
-        result_str = "Given parameter is invalid";
-        break;
-    default:
-        result_str = "Unknown error";
-        break;
-    }
-    return result_str;
-}
-
-static FRESULT sd_mount_fs(void)
-{
-    FRESULT fresult = f_mount(&s_sd_disk, driver_num_buf, 1);
-    if (fresult == FR_OK) {
-        printf("SD card has been mounted successfully\n");
-    } else {
-        printf("Failed to mount SD card, cause: %s\n", show_error_string(fresult));
-    }
-
-    fresult = f_chdrive(driver_num_buf);
-    return fresult;
-}
-
-static FRESULT sd_mkfs(void)
-{
-    printf("Formatting the SD card, depending on the SD card capacity, the formatting process may take a long time\n");
-    FRESULT fresult = f_mkfs(driver_num_buf, NULL, work, sizeof(work));
-    if (fresult != FR_OK) {
-        printf("Making File system failed, cause: %s\n", show_error_string(fresult));
-    } else {
-        printf("Making file system is successful\n");
-    }
-
-    return fresult;
-}
-void SD1_test(void)
-{ 
-    bool need_init_filesystem = true;
-    board_init();
-   
-    /* Before doing FATFS operation, ensure the SD card is present */
-    DSTATUS dstatus = disk_status(DEV_SD);
-    if (dstatus == STA_NODISK) {
-        printf("No disk in the SD slot, please insert an SD card...\n");
-        do {
-            dstatus = disk_status(DEV_SD);
-        } while (dstatus == STA_NODISK);
-        board_delay_ms(100);
-        printf("Detected SD card, re-initialize the filesystem...\n");
-        need_init_filesystem = true;
-    }
-    dstatus = disk_initialize(DEV_SD);
-    if (dstatus != RES_OK) {
-        printf("Failed to initialize SD disk\n");
-    }
-    if (need_init_filesystem) {
-        fatfs_result = sd_mount_fs();
-        if (fatfs_result == FR_NO_FILESYSTEM) {
-            printf("There is no File system available, making file system...\n");
-            fatfs_result = sd_mkfs();
-            if (fatfs_result != FR_OK) {
-                printf("Failed to make filesystem, cause:%s\n", show_error_string(fatfs_result));
-            } else {
-                need_init_filesystem = false;
-            }
-        }
-    }
-}
- 
-
 #endif

+ 2 - 2
controller_yy_app/hardware/hard_system.c

@@ -23,8 +23,8 @@ void sys_reset(void)
  */
 void u3_dma_disable(void)
 {
-    // 禁用HDMA通道 1
-    dma_disable_channel(U3_DMA, U3_DMA_CH); 
+    // 禁用HDMA通道 1 根据实际修改
+   // dma_disable_channel(U3_DMA, U3_DMA_CH); 
     
 }
 

+ 2 - 0
controller_yy_app/software/debug_printf.c

@@ -1,4 +1,6 @@
+// 使用uart0来进行调试日子的打印
 #if 0
+
 #include "stm32f4xx.h"
 #include <stdio.h>
 

+ 3 - 1
controller_yy_app/software/soft_can.c

@@ -7,6 +7,7 @@
 #include "soft_time.h"
 #include "ver_config.h"
 #include "soft_can_yy.h"
+#include "test.h"
 // 宏定义与hard can同步修改
 #define CAN2         HPM_CAN2
 #define CAN2_IRQ     IRQn_CAN2
@@ -160,7 +161,7 @@ void CanTxRxServicePoll(void)
     YY_tx_loop();
 }
 static volatile bool has_sent_out;
-
+#ifndef TEST_EN
 SDK_DECLARE_EXT_ISR_M(CAN2_IRQ, can2_isr)
 void can2_isr(void)
 {
@@ -199,3 +200,4 @@ void can2_isr(void)
         can_clear_error_interrupt_flags(CAN2, error_flags);
     }
 }
+#endif

+ 599 - 0
controller_yy_app/software/soft_flash.c

@@ -19,6 +19,7 @@
 #include "bsp_V8M_YY_pwm.h"
 #include "hard_system.h"
 #include <string.h>
+#include "test.h"
 
 #ifdef GD25Q16_FLASH
 #include "hard_flash_gd25q16.h"
@@ -845,3 +846,601 @@ void write_par_to_flash(void)
 }
 
 //------------------End of File----------------------------
+#ifdef SOFT_FLASH_TEST
+
+//============================================================================
+// GD25Q16 芯片参数
+//============================================================================
+#define GD25Q16_TOTAL_SIZE      (2 * 1024 * 1024)  // 2MB
+#define GD25Q16_PAGE_SIZE       256                 // 页大小 256 字节
+#define GD25Q16_SECTOR_SIZE     (4 * 1024)          // 扇区大小 4KB
+#define GD25Q16_BLOCK_SIZE      (64 * 1024)         // 块大小 64KB
+#define GD25Q16_TOTAL_PAGES     (GD25Q16_TOTAL_SIZE / GD25Q16_PAGE_SIZE)  // 8192 页
+#define GD25Q16_TOTAL_SECTORS   (GD25Q16_TOTAL_SIZE / GD25Q16_SECTOR_SIZE) // 512 扇区
+
+//============================================================================
+// 根据您的地址划分重新计算(基于实际地址,不是页索引)
+//============================================================================
+// 您的地址定义(基于字节地址)
+#define IAP_ADDR                (512 * 5)           // 0x00000A00
+#define pidinf_addr             (512 * 16)          // 0x00002000
+#define verinf_addr             (512 * 24)          // 0x00003000
+#define confinf_addr            (512 * 32)          // 0x00004000
+#define caminf_addr             (512 * 40)          // 0x00005000
+#define parinf_addr             (512 * 48)          // 0x00006000
+#define POS_TOTAL_ADDR          (512 * 56)          // 0x00007000
+#define NO_FLY_ZONE_ADDR        (512 * 64)          // 0x00008000
+#define FPALTCHANGE_ADDR        (512 * 80)          // 0x0000A000
+#define BREAKPOINT_ADDR         (512 * 88)          // 0x0000B000
+#define WAYPOINT_ADDR           (512 * 96)          // 0x0000C000
+#define POS_START_PAGE          200                 // 页索引 200 = 0x0000C800? 需要重新计算
+
+//============================================================================
+// 测试区域定义 - 使用 Flash 末尾的安全区域(最后 256KB)
+//============================================================================
+#define TEST_AREA_START         (GD25Q16_TOTAL_SIZE - 256 * 1024)  // 最后 256KB (0x1C0000)
+#define TEST_AREA_SIZE          (256 * 1024)                        // 256KB 测试空间
+#define TEST_AREA_END           (TEST_AREA_START + TEST_AREA_SIZE)
+
+// 测试地址验证
+#define IS_TEST_ADDR(addr) \
+    ((addr) >= TEST_AREA_START && (addr) < TEST_AREA_END)
+
+//============================================================================
+// 全局测试变量
+//============================================================================
+static bool test_passed = true;
+static uint32_t test_count = 0;
+static uint32_t fail_count = 0;
+
+// 缓冲区
+static uint8_t g_test_buffer[GD25Q16_PAGE_SIZE * 4];  // 4页缓冲区
+
+//============================================================================
+// 辅助函数
+//============================================================================
+
+/**
+ * @brief 打印测试结果
+ */
+static void print_result(const char* test_name, bool passed)
+{
+    if (passed) {
+        printf("[PASS] %s\n", test_name);
+        test_count++;
+    } else {
+        printf("[FAIL] %s\n", test_name);
+        fail_count++;
+        test_passed = false;
+    }
+}
+
+/**
+ * @brief 打印十六进制数据
+ */
+static void print_hex(const uint8_t* data, uint16_t len, const char* title)
+{
+    printf("%s:\n", title);
+    for (uint16_t i = 0; i < len; i++) {
+        if (i % 16 == 0 && i != 0) printf("\n");
+        printf("%02X ", data[i]);
+    }
+    printf("\n");
+}
+
+/**
+ * @brief 保存测试区域数据
+ */
+static void save_test_area(uint32_t addr, uint32_t len)
+{
+    if (len > sizeof(g_test_buffer)) {
+        len = sizeof(g_test_buffer);
+    }
+    printf("  Saving data at 0x%06X...\n", addr);
+    flash_read_bytes(addr, g_test_buffer, len);
+}
+
+/**
+ * @brief 恢复测试区域数据
+ */
+static void restore_test_area(uint32_t addr, uint32_t len)
+{
+    if (len > sizeof(g_test_buffer)) {
+        len = sizeof(g_test_buffer);
+    }
+    printf("  Restoring data at 0x%06X...\n", addr);
+    flash_write_bytes(addr, g_test_buffer, len);
+    delay_ms(20);
+}
+
+//============================================================================
+// 测试用例
+//============================================================================
+
+/**
+ * @brief 测试0: 显示 Flash 信息和地址布局
+ */
+void test_flash_info(void)
+{
+    printf("\n=== Test 0: Flash Information ===\n");
+    printf("Chip: GD25Q16 (16Mbit SPI Flash)\n");
+    printf("Total Size: %d bytes (%d MB)\n", GD25Q16_TOTAL_SIZE, GD25Q16_TOTAL_SIZE / 1024 / 1024);
+    printf("Page Size: %d bytes\n", GD25Q16_PAGE_SIZE);
+    printf("Sector Size: %d bytes (%d KB)\n", GD25Q16_SECTOR_SIZE, GD25Q16_SECTOR_SIZE / 1024);
+    printf("Block Size: %d bytes (%d KB)\n", GD25Q16_BLOCK_SIZE, GD25Q16_BLOCK_SIZE / 1024);
+    printf("Total Pages: %d\n", GD25Q16_TOTAL_PAGES);
+    printf("Total Sectors: %d\n", GD25Q16_TOTAL_SECTORS);
+    
+    printf("\n--- User Config Areas ---\n");
+    printf("  IAP_ADDR         : 0x%06X\n", IAP_ADDR);
+    printf("  pidinf_addr      : 0x%06X\n", pidinf_addr);
+    printf("  verinf_addr      : 0x%06X\n", verinf_addr);
+    printf("  confinf_addr     : 0x%06X\n", confinf_addr);
+    printf("  caminf_addr      : 0x%06X\n", caminf_addr);
+    printf("  parinf_addr      : 0x%06X\n", parinf_addr);
+    printf("  POS_TOTAL_ADDR   : 0x%06X\n", POS_TOTAL_ADDR);
+    printf("  NO_FLY_ZONE_ADDR : 0x%06X\n", NO_FLY_ZONE_ADDR);
+    printf("  WAYPOINT_ADDR    : 0x%06X\n", WAYPOINT_ADDR);
+    
+    printf("\n--- Test Safe Area ---\n");
+    printf("  TEST_AREA_START  : 0x%06X\n", TEST_AREA_START);
+    printf("  TEST_AREA_END    : 0x%06X\n", TEST_AREA_END);
+    printf("  TEST_AREA_SIZE   : %d bytes (%d KB)\n", TEST_AREA_SIZE, TEST_AREA_SIZE / 1024);
+    
+    print_result("Flash info display", true);
+}
+
+/**
+ * @brief 测试1: 页读写测试 (256字节)
+ */
+void test_page_rw(void)
+{
+    uint32_t test_addr = TEST_AREA_START;
+    uint8_t write_buf[GD25Q16_PAGE_SIZE];
+    uint8_t read_buf[GD25Q16_PAGE_SIZE];
+    
+    printf("\n=== Test 1: Page (256 bytes) Read/Write ===\n");
+    
+    // 准备数据
+    for (int i = 0; i < GD25Q16_PAGE_SIZE; i++) {
+        write_buf[i] = i & 0xFF;
+    }
+    
+    // 保存原始数据
+    save_test_area(test_addr, GD25Q16_PAGE_SIZE);
+    
+    // 写入
+    printf("  Writing page at 0x%06X...\n", test_addr);
+    flash_write_bytes(test_addr, write_buf, GD25Q16_PAGE_SIZE);
+    delay_ms(10);
+    
+    // 读取
+    memset(read_buf, 0, sizeof(read_buf));
+    flash_read_bytes(test_addr, read_buf, GD25Q16_PAGE_SIZE);
+    
+    // 验证
+    bool match = (memcmp(write_buf, read_buf, GD25Q16_PAGE_SIZE) == 0);
+    if (!match) {
+        printf("  Mismatch detected!\n");
+        for (int i = 0; i < 16; i++) {
+            if (write_buf[i] != read_buf[i]) {
+                printf("    Byte %d: 0x%02X vs 0x%02X\n", i, write_buf[i], read_buf[i]);
+                break;
+            }
+        }
+    }
+    
+    // 恢复
+    restore_test_area(test_addr, GD25Q16_PAGE_SIZE);
+    
+    print_result("Page read/write", match);
+}
+
+/**
+ * @brief 测试2: 多页读写测试 (4页 = 1KB)
+ */
+void test_multipage_rw(void)
+{
+    uint32_t test_addr = TEST_AREA_START + GD25Q16_PAGE_SIZE;
+    uint16_t page_count = 4;
+    uint32_t test_len = page_count * GD25Q16_PAGE_SIZE;
+    uint8_t* write_buf = g_test_buffer;
+    uint8_t read_buf[GD25Q16_PAGE_SIZE * 4];
+    
+    printf("\n=== Test 2: Multi-Page (%d pages) Read/Write ===\n", page_count);
+    
+    // 准备数据
+    for (int i = 0; i < test_len; i++) {
+        write_buf[i] = (i + 0x80) & 0xFF;
+    }
+    
+    // 保存原始数据
+    save_test_area(test_addr, test_len);
+    
+    // 写入
+    printf("  Writing %d bytes at 0x%06X...\n", test_len, test_addr);
+    flash_write_bytes(test_addr, write_buf, test_len);
+    delay_ms(20);
+    
+    // 读取
+    memset(read_buf, 0, sizeof(read_buf));
+    flash_read_bytes(test_addr, read_buf, test_len);
+    
+    // 验证
+    bool match = (memcmp(write_buf, read_buf, test_len) == 0);
+    
+    // 恢复
+    restore_test_area(test_addr, test_len);
+    
+    print_result("Multi-page read/write", match);
+}
+
+/**
+ * @brief 测试3: 扇区擦除测试 (4KB)
+ */
+void test_sector_erase(void)
+{
+    uint32_t test_addr = TEST_AREA_START + GD25Q16_SECTOR_SIZE;
+    uint32_t sector_start = (test_addr / GD25Q16_SECTOR_SIZE) * GD25Q16_SECTOR_SIZE;
+    uint8_t* read_buf = g_test_buffer;
+    
+    printf("\n=== Test 3: Sector (4KB) Erase Test ===\n");
+    printf("  Sector start: 0x%06X\n", sector_start);
+    
+    // 先写入非0xFF数据
+    memset(g_test_buffer, 0xA5, GD25Q16_SECTOR_SIZE);
+    flash_write_bytes(sector_start, g_test_buffer, GD25Q16_SECTOR_SIZE);
+    delay_ms(20);
+    
+    // 保存原始数据用于恢复
+    save_test_area(sector_start, GD25Q16_SECTOR_SIZE);
+    
+    // 擦除扇区
+    printf("  Erasing sector...\n");
+    // 注意: 这里需要调用扇区擦除函数,如果您的驱动没有单独的函数,
+    // 可以通过写入0xFF来实现,或者调用底层擦除函数
+    // AT45DB_EraseSector(sector_start);  // 如果有这个函数
+    // 暂时用写入0xFF模拟(实际应该用擦除命令)
+    memset(g_test_buffer, 0xFF, GD25Q16_SECTOR_SIZE);
+    flash_write_bytes(sector_start, g_test_buffer, GD25Q16_SECTOR_SIZE);
+    delay_ms(50);
+    
+    // 读取验证
+    memset(read_buf, 0, GD25Q16_SECTOR_SIZE);
+    flash_read_bytes(sector_start, read_buf, GD25Q16_SECTOR_SIZE);
+    
+    // 验证是否全为0xFF
+    bool all_ff = true;
+    for (int i = 0; i < GD25Q16_SECTOR_SIZE; i++) {
+        if (read_buf[i] != 0xFF) {
+            all_ff = false;
+            printf("  Non-0xFF at offset %d: 0x%02X\n", i, read_buf[i]);
+            break;
+        }
+    }
+    
+    // 恢复原始数据
+    restore_test_area(sector_start, GD25Q16_SECTOR_SIZE);
+    
+    print_result("Sector erase", all_ff);
+}
+
+/**
+ * @brief 测试4: 边界地址测试
+ */
+void test_boundary(void)
+{
+    uint8_t write_buf[32];
+    uint8_t read_buf[32];
+    uint32_t boundary_addr = TEST_AREA_END - 16;
+    
+    printf("\n=== Test 4: Boundary Address Test ===\n");
+    printf("  Boundary address: 0x%06X\n", boundary_addr);
+    
+    if (!IS_TEST_ADDR(boundary_addr) || !IS_TEST_ADDR(boundary_addr + 16)) {
+        printf("  Skipping (address out of test area)\n");
+        print_result("Boundary test", true);
+        return;
+    }
+    
+    // 准备数据
+    for (int i = 0; i < sizeof(write_buf); i++) {
+        write_buf[i] = 0x55 + i;
+    }
+    
+    // 保存
+    save_test_area(boundary_addr, sizeof(write_buf));
+    
+    // 写入
+    flash_write_bytes(boundary_addr, write_buf, sizeof(write_buf));
+    delay_ms(10);
+    
+    // 读取
+    flash_read_bytes(boundary_addr, read_buf, sizeof(read_buf));
+    
+    // 验证
+    bool match = (memcmp(write_buf, read_buf, sizeof(write_buf)) == 0);
+    
+    // 恢复
+    restore_test_area(boundary_addr, sizeof(write_buf));
+    
+    print_result("Boundary test", match);
+}
+
+/**
+ * @brief 测试5: 16位整数读写测试
+ */
+void test_int16_rw(void)
+{
+    uint32_t test_addr = TEST_AREA_START + 0x2000;
+    int16_t write_vals[] = {0, 1, -1, 32767, -32768, 0x1234, 0x5678, 0x9ABC, 0xDEF0};
+    int16_t read_vals[9];
+    
+    printf("\n=== Test 5: Int16 Read/Write Test ===\n");
+    
+    // 保存原始数据
+    save_test_area(test_addr, sizeof(write_vals));
+    
+    bool all_match = true;
+    for (int i = 0; i < sizeof(write_vals)/sizeof(write_vals[0]); i++) {
+        uint32_t addr = test_addr + i * 2;
+        flash_write_int16(addr, write_vals[i]);
+        delay_ms(5);
+        read_vals[i] = flash_read_int16(addr);
+        
+        if (read_vals[i] != write_vals[i]) {
+            printf("  Mismatch at 0x%06X: %d vs %d\n", addr, write_vals[i], read_vals[i]);
+            all_match = false;
+        }
+    }
+    
+    if (all_match) {
+        printf("  All %d values match\n", (int)(sizeof(write_vals)/sizeof(write_vals[0])));
+    }
+    
+    // 恢复
+    restore_test_area(test_addr, sizeof(write_vals));
+    
+    print_result("Int16 read/write", all_match);
+}
+
+/**
+ * @brief 测试6: 压力测试
+ */
+void test_stress(void)
+{
+    uint32_t test_addr = TEST_AREA_START + 0x3000;
+    uint32_t test_len = 256;
+    uint8_t* write_buf = g_test_buffer;
+    uint8_t read_buf[256];
+    const int cycles = 30;
+    
+    printf("\n=== Test 6: Stress Test (%d cycles) ===\n", cycles);
+    
+    // 保存原始数据
+    save_test_area(test_addr, test_len);
+    
+    int failed = 0;
+    for (int cycle = 0; cycle < cycles; cycle++) {
+        // 准备数据
+        for (int i = 0; i < test_len; i++) {
+            if (cycle % 3 == 0) write_buf[i] = cycle & 0xFF;
+            else if (cycle % 3 == 1) write_buf[i] = 0x55;
+            else write_buf[i] = 0xAA;
+        }
+        
+        flash_write_bytes(test_addr, write_buf, test_len);
+        delay_ms(5);
+        
+        flash_read_bytes(test_addr, read_buf, test_len);
+        
+        if (memcmp(write_buf, read_buf, test_len) != 0) {
+            failed++;
+            printf("  Cycle %d failed\n", cycle);
+        }
+        
+        if ((cycle + 1) % 10 == 0) {
+            printf("  Progress: %d/%d\n", cycle + 1, cycles);
+        }
+    }
+    
+    printf("  Failed: %d/%d\n", failed, cycles);
+    
+    // 恢复
+    restore_test_area(test_addr, test_len);
+    
+    print_result("Stress test", failed == 0);
+}
+
+/**
+ * @brief 测试7: 随机模式测试
+ */
+void test_random_pattern(void)
+{
+    uint32_t test_addr = TEST_AREA_START + 0x4000;
+    uint32_t test_len = 512;
+    uint8_t* write_buf = g_test_buffer;
+    uint8_t read_buf[512];
+    
+    printf("\n=== Test 7: Random Pattern Test ===\n");
+    
+    // 生成随机数据
+    for (int i = 0; i < test_len; i++) {
+        write_buf[i] = (i * 0x9E3779B9) ^ (i >> 3);
+        write_buf[i] = (write_buf[i] ^ (write_buf[i] >> 4)) & 0xFF;
+    }
+    
+    // 保存
+    save_test_area(test_addr, test_len);
+    
+    // 写入
+    flash_write_bytes(test_addr, write_buf, test_len);
+    delay_ms(15);
+    
+    // 读取
+    flash_read_bytes(test_addr, read_buf, test_len);
+    
+    // 验证
+    bool match = (memcmp(write_buf, read_buf, test_len) == 0);
+    if (!match) {
+        for (int i = 0; i < 20; i++) {
+            if (write_buf[i] != read_buf[i]) {
+                printf("  First mismatch at %d: 0x%02X vs 0x%02X\n", 
+                       i, write_buf[i], read_buf[i]);
+                break;
+            }
+        }
+    }
+    
+    // 恢复
+    restore_test_area(test_addr, test_len);
+    
+    print_result("Random pattern", match);
+}
+
+/**
+ * @brief 测试8: 数据完整性测试(写入后立即读取多次)
+ */
+void test_integrity(void)
+{
+    uint32_t test_addr = TEST_AREA_START + 0x5000;
+    uint16_t test_values[] = {0x1234, 0x5678, 0x9ABC, 0xDEF0, 0xABCD, 0xFFFF, 0x0000};
+    
+    printf("\n=== Test 8: Data Integrity Test ===\n");
+    
+    // 保存原始数据
+    save_test_area(test_addr, sizeof(test_values));
+    
+    bool all_match = true;
+    for (int i = 0; i < sizeof(test_values)/sizeof(test_values[0]); i++) {
+        uint32_t addr = test_addr + i * 2;
+        
+        // 写入
+        flash_write_int16(addr, test_values[i]);
+        delay_ms(5);
+        
+        // 多次读取验证
+        for (int read_count = 0; read_count < 3; read_count++) {
+            int16_t read_val = flash_read_int16(addr);
+            if (read_val != test_values[i]) {
+                printf("  Value 0x%04X at 0x%06X: read %d/3 = 0x%04X\n",
+                       test_values[i], addr, read_count + 1, read_val);
+                all_match = false;
+                break;
+            }
+        }
+    }
+    
+    if (all_match) {
+        printf("  All values passed integrity check\n");
+    }
+    
+    // 恢复
+    restore_test_area(test_addr, sizeof(test_values));
+    
+    print_result("Data integrity", all_match);
+}
+
+//============================================================================
+// 主测试函数
+//============================================================================
+
+/**
+ * @brief 运行完整测试
+ */
+void run_flash_test(void)
+{
+    printf("\n");
+    printf("╔══════════════════════════════════════════════════════════════╗\n");
+    printf("║           GD25Q16 Flash Test Suite (Safe Area Mode)         ║\n");
+    printf("╚══════════════════════════════════════════════════════════════╝\n");
+    printf("Chip: GD25Q16 (16Mbit = 2MB)\n");
+    printf("Test Area: 0x%06X - 0x%06X (%d KB)\n", 
+           TEST_AREA_START, TEST_AREA_END, TEST_AREA_SIZE / 1024);
+    
+    // 初始化
+    printf("\nInitializing Flash...\n");
+    flash_at45db_initial();  // 实际是 GD25Q16 驱动
+    delay_ms(100);
+    
+    if (!flash_isexist()) {
+        printf("ERROR: Flash not detected!\n");
+        return;
+    }
+    printf("Flash detected, status: %s\n", flash_isbusy() ? "Busy" : "Ready");
+    
+    // 重置计数
+    test_count = 0;
+    fail_count = 0;
+    test_passed = true;
+    
+    // 运行测试
+    test_flash_info();
+    test_page_rw();
+    test_multipage_rw();
+    test_sector_erase();
+    test_boundary();
+    test_int16_rw();
+    test_random_pattern();
+    test_integrity();
+    test_stress();
+    
+    // 结果
+    printf("\n");
+    printf("══════════════════════════════════════════════════════════════\n");
+    printf("Test Summary:\n");
+    printf("  Total: %d\n", test_count + fail_count);
+    printf("  Passed: %d\n", test_count);
+    printf("  Failed: %d\n", fail_count);
+    printf("══════════════════════════════════════════════════════════════\n");
+    
+    if (test_passed) {
+        printf("\n✓ ALL TESTS PASSED!\n");
+    } else {
+        printf("\n✗ SOME TESTS FAILED!\n");
+    }
+}
+
+/**
+ * @brief 快速功能测试
+ */
+void run_flash_quick_test(void)
+{
+    uint8_t test_data[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0};
+    uint8_t read_data[8];
+    uint32_t test_addr = TEST_AREA_START;
+    
+    printf("\n=== Quick Test ===\n");
+    
+    flash_at45db_initial();
+    delay_ms(100);
+    
+    if (!flash_isexist()) {
+        printf("Flash not detected!\n");
+        return;
+    }
+    
+    // 保存
+    uint8_t original[8];
+    flash_read_bytes(test_addr, original, sizeof(original));
+    
+    // 测试
+    flash_write_bytes(test_addr, test_data, sizeof(test_data));
+    delay_ms(10);
+    flash_read_bytes(test_addr, read_data, sizeof(read_data));
+    
+    if (memcmp(test_data, read_data, sizeof(test_data)) == 0) {
+        printf("TEST PASSED\n");
+        printf("Data: ");
+        for (int i = 0; i < sizeof(test_data); i++) {
+            printf("%02X ", read_data[i]);
+        }
+        printf("\n");
+    } else {
+        printf("TEST FAILED\n");
+    }
+    
+    // 恢复
+    flash_write_bytes(test_addr, original, sizeof(original));
+}
+#endif

+ 0 - 1
controller_yy_app/software/soft_inc/soft_sdcard.h

@@ -18,6 +18,5 @@ uint8_t sdcard_initok(void);
 
 void sdcard_inital(uint8_t init_type);
 
-void main_test_demo(void);
 
 #endif

+ 1 - 0
controller_yy_app/software/soft_inc/soft_time.h

@@ -8,4 +8,5 @@ unsigned int micros(void);
 
 unsigned int time_interval(unsigned int time_cur, unsigned int *time_last);
 
+
 #endif

+ 614 - 1
controller_yy_app/software/soft_motor_output.c

@@ -18,7 +18,7 @@
 #include "soft_time.h"
 #include "soft_timer.h"
 #include "ver_config.h"
-
+#include "test.h"
 /*-------------------- Macros definition -------------------------------------*/
 
 /* 控制量混控 */
@@ -969,3 +969,616 @@ uint8_t Motor_GetFailsafeNum(void)
 {
     return _motor_failsafe_num;
 }
+
+
+#ifdef SOFT_MOTOR_TEST
+//============================================================================
+// 测试配置
+//============================================================================
+#define TEST_MOTOR_COUNT    4           // 四轴电机数量
+#define TEST_DURATION_MS    5000        // 每个测试持续时间 5秒
+#define TEST_STEP_DELAY_MS  2000        // 测试步骤间隔 2秒
+
+// 测试模式
+typedef enum {
+    TEST_MODE_IDLE = 0,         // 怠速测试
+    TEST_MODE_HOVER,            // 悬停测试
+    TEST_MODE_ROLL,             // 横滚测试
+    TEST_MODE_PITCH,            // 俯仰测试
+    TEST_MODE_YAW,              // 偏航测试
+    TEST_MODE_THROTTLE,         // 油门测试
+    TEST_MODE_SATURATION,       // 饱和保护测试
+    TEST_MODE_END               // 结束
+} test_mode_t;
+
+// 测试结果
+typedef struct {
+    uint16_t motor_values[8];   // 电机输出值
+    float pid_roll;             // 横滚PID输出
+    float pid_pitch;            // 俯仰PID输出
+    float pid_yaw;              // 偏航PID输出
+    float pid_thr;              // 油门PID输出
+    uint8_t yaw_restricted;     // 偏航受限标志
+    uint32_t timestamp;         // 时间戳
+} motor_test_data_t;
+
+//============================================================================
+// 全局测试变量
+//============================================================================
+static motor_test_data_t g_test_data[100];  // 存储测试数据
+static uint16_t g_data_index = 0;
+static bool g_test_running = false;
+
+//============================================================================
+// 辅助函数
+//============================================================================
+
+/**
+ * @brief 打印电机输出值
+ */
+static void print_motor_values(uint16_t *motors, uint8_t count, const char* title)
+{
+    printf("%s: ", title);
+    for (int i = 0; i < count; i++) {
+        printf("M%d=%d ", i+1, motors[i]);
+    }
+    printf("\n");
+}
+
+/**
+ * @brief 记录测试数据
+ */
+static void record_test_data(void)
+{
+    if (g_data_index < sizeof(g_test_data)/sizeof(g_test_data[0])) {
+        g_test_data[g_data_index].timestamp = micros();
+        
+        // 读取当前电机输出
+        for (int i = 0; i < TEST_MOTOR_COUNT; i++) {
+            g_test_data[g_data_index].motor_values[i] = get_motor_pwm(i+1);
+        }
+        
+        // 记录PID值(从全局变量获取)
+        extern float pid_roll, pid_pitch, pid_yaw, pid_thr;
+        g_test_data[g_data_index].pid_roll = pid_roll;
+        g_test_data[g_data_index].pid_pitch = pid_pitch;
+        g_test_data[g_data_index].pid_yaw = pid_yaw;
+        g_test_data[g_data_index].pid_thr = pid_thr;
+        
+        // 记录偏航受限标志
+        g_test_data[g_data_index].yaw_restricted = MotorOutput_GetYawRestrictionStatus();
+        
+        g_data_index++;
+    }
+}
+
+/**
+ * @brief 打印测试总结
+ */
+static void print_test_summary(void)
+{
+    printf("\n========== Test Summary ==========\n");
+    printf("Total records: %d\n", g_data_index);
+    
+    if (g_data_index > 0) {
+        printf("\nLast record:\n");
+        printf("  Time: %lu us\n", g_test_data[g_data_index-1].timestamp);
+        printf("  Motors: ");
+        for (int i = 0; i < TEST_MOTOR_COUNT; i++) {
+            printf("%d ", g_test_data[g_data_index-1].motor_values[i]);
+        }
+        printf("\n");
+        printf("  PID: roll=%.2f, pitch=%.2f, yaw=%.2f, thr=%.2f\n",
+               g_test_data[g_data_index-1].pid_roll,
+               g_test_data[g_data_index-1].pid_pitch,
+               g_test_data[g_data_index-1].pid_yaw,
+               g_test_data[g_data_index-1].pid_thr);
+        printf("  Yaw restricted: %d\n", g_test_data[g_data_index-1].yaw_restricted);
+    }
+    printf("==================================\n");
+}
+
+//============================================================================
+// 测试函数
+//============================================================================
+
+/**
+ * @brief 测试1: 怠速输出测试
+ * @note 测试电机在锁状态下的怠速输出
+ */
+void test_motor_idle_output(void)
+{
+    printf("\n=== Test 1: Idle Output Test ===\n");
+    printf("Expected: All motors output idle speed (%d us)\n", Min_PWM_Out);
+    
+    // 确保处于锁定状态
+    thr_lock_status = LOCKED;
+    
+    // 运行电机输出函数
+    for (int i = 0; i < 100; i++) {
+        locked_motor_output();
+        delay_ms(10);
+        
+        if (i % 20 == 0) {
+            uint16_t motors[4];
+            for (int j = 0; j < TEST_MOTOR_COUNT; j++) {
+                motors[j] = get_motor_pwm(j+1);
+            }
+            print_motor_values(motors, TEST_MOTOR_COUNT, "  Motors");
+        }
+    }
+    
+    printf("Idle output test completed\n");
+}
+
+/**
+ * @brief 测试2: 悬停状态混控测试
+ * @note 模拟悬停状态,测试电机混控输出
+ */
+void test_motor_hover_mix(void)
+{
+    printf("\n=== Test 2: Hover Mix Test ===\n");
+    printf("Setting: roll=0, pitch=0, yaw=0, throttle=middle\n");
+    
+    // 设置悬停状态
+    extern float pid_roll, pid_pitch, pid_yaw, pid_thr;
+    pid_roll = 0.0f;
+    pid_pitch = 0.0f;
+    pid_yaw = 0.0f;
+    pid_thr = 1500.0f;  // 悬停油门
+    
+    // 设置解锁定状态
+    thr_lock_status = UNLOCKED;
+    ground_air_status = IN_AIR;
+    
+    // 运行电机输出
+    for (int i = 0; i < 50; i++) {
+        unlocked_motor_output();
+        delay_ms(20);
+        
+        if (i % 10 == 0) {
+            uint16_t motors[4];
+            for (int j = 0; j < TEST_MOTOR_COUNT; j++) {
+                motors[j] = get_motor_pwm(j+1);
+            }
+            print_motor_values(motors, TEST_MOTOR_COUNT, "  Hover");
+        }
+    }
+    
+    printf("Hover mix test completed\n");
+}
+
+/**
+ * @brief 测试3: 横滚响应测试
+ * @note 测试横滚控制时的电机响应
+ */
+void test_motor_roll_response(void)
+{
+    printf("\n=== Test 3: Roll Response Test ===\n");
+    
+    extern float pid_roll, pid_pitch, pid_yaw, pid_thr;
+    pid_pitch = 0.0f;
+    pid_yaw = 0.0f;
+    pid_thr = 1500.0f;
+    
+    thr_lock_status = UNLOCKED;
+    ground_air_status = IN_AIR;
+    
+    // 测试正横滚
+    printf("Positive roll (+100):\n");
+    pid_roll = 100.0f;
+    for (int i = 0; i < 25; i++) {
+        unlocked_motor_output();
+        delay_ms(20);
+        if (i % 10 == 0) {
+            uint16_t motors[4];
+            for (int j = 0; j < TEST_MOTOR_COUNT; j++) {
+                motors[j] = get_motor_pwm(j+1);
+            }
+            print_motor_values(motors, TEST_MOTOR_COUNT, "    Motors");
+        }
+    }
+    
+    delay_ms(1000);
+    
+    // 测试负横滚
+    printf("Negative roll (-100):\n");
+    pid_roll = -100.0f;
+    for (int i = 0; i < 25; i++) {
+        unlocked_motor_output();
+        delay_ms(20);
+        if (i % 10 == 0) {
+            uint16_t motors[4];
+            for (int j = 0; j < TEST_MOTOR_COUNT; j++) {
+                motors[j] = get_motor_pwm(j+1);
+            }
+            print_motor_values(motors, TEST_MOTOR_COUNT, "    Motors");
+        }
+    }
+    
+    printf("Roll response test completed\n");
+}
+
+/**
+ * @brief 测试4: 俯仰响应测试
+ */
+void test_motor_pitch_response(void)
+{
+    printf("\n=== Test 4: Pitch Response Test ===\n");
+    
+    extern float pid_roll, pid_pitch, pid_yaw, pid_thr;
+    pid_roll = 0.0f;
+    pid_yaw = 0.0f;
+    pid_thr = 1500.0f;
+    
+    thr_lock_status = UNLOCKED;
+    ground_air_status = IN_AIR;
+    
+    // 测试正俯仰
+    printf("Positive pitch (+100):\n");
+    pid_pitch = 100.0f;
+    for (int i = 0; i < 25; i++) {
+        unlocked_motor_output();
+        delay_ms(20);
+        if (i % 10 == 0) {
+            uint16_t motors[4];
+            for (int j = 0; j < TEST_MOTOR_COUNT; j++) {
+                motors[j] = get_motor_pwm(j+1);
+            }
+            print_motor_values(motors, TEST_MOTOR_COUNT, "    Motors");
+        }
+    }
+    
+    delay_ms(1000);
+    
+    // 测试负俯仰
+    printf("Negative pitch (-100):\n");
+    pid_pitch = -100.0f;
+    for (int i = 0; i < 25; i++) {
+        unlocked_motor_output();
+        delay_ms(20);
+        if (i % 10 == 0) {
+            uint16_t motors[4];
+            for (int j = 0; j < TEST_MOTOR_COUNT; j++) {
+                motors[j] = get_motor_pwm(j+1);
+            }
+            print_motor_values(motors, TEST_MOTOR_COUNT, "    Motors");
+        }
+    }
+    
+    printf("Pitch response test completed\n");
+}
+
+/**
+ * @brief 测试5: 偏航响应测试
+ */
+void test_motor_yaw_response(void)
+{
+    printf("\n=== Test 5: Yaw Response Test ===\n");
+    
+    extern float pid_roll, pid_pitch, pid_yaw, pid_thr;
+    pid_roll = 0.0f;
+    pid_pitch = 0.0f;
+    pid_thr = 1500.0f;
+    
+    thr_lock_status = UNLOCKED;
+    ground_air_status = IN_AIR;
+    
+    // 测试正偏航
+    printf("Positive yaw (+100):\n");
+    pid_yaw = 100.0f;
+    for (int i = 0; i < 25; i++) {
+        unlocked_motor_output();
+        delay_ms(20);
+        if (i % 10 == 0) {
+            uint16_t motors[4];
+            for (int j = 0; j < TEST_MOTOR_COUNT; j++) {
+                motors[j] = get_motor_pwm(j+1);
+            }
+            print_motor_values(motors, TEST_MOTOR_COUNT, "    Motors");
+        }
+    }
+    
+    delay_ms(1000);
+    
+    // 测试负偏航
+    printf("Negative yaw (-100):\n");
+    pid_yaw = -100.0f;
+    for (int i = 0; i < 25; i++) {
+        unlocked_motor_output();
+        delay_ms(20);
+        if (i % 10 == 0) {
+            uint16_t motors[4];
+            for (int j = 0; j < TEST_MOTOR_COUNT; j++) {
+                motors[j] = get_motor_pwm(j+1);
+            }
+            print_motor_values(motors, TEST_MOTOR_COUNT, "    Motors");
+        }
+    }
+    
+    printf("Yaw response test completed\n");
+}
+
+/**
+ * @brief 测试6: 油门响应测试
+ */
+void test_motor_throttle_response(void)
+{
+    printf("\n=== Test 6: Throttle Response Test ===\n");
+    
+    extern float pid_roll, pid_pitch, pid_yaw, pid_thr;
+    pid_roll = 0.0f;
+    pid_pitch = 0.0f;
+    pid_yaw = 0.0f;
+    
+    thr_lock_status = UNLOCKED;
+    ground_air_status = IN_AIR;
+    
+    // 测试低油门
+    printf("Low throttle (1200):\n");
+    pid_thr = 1200.0f;
+    for (int i = 0; i < 25; i++) {
+        unlocked_motor_output();
+        delay_ms(20);
+        if (i % 10 == 0) {
+            uint16_t motors[4];
+            for (int j = 0; j < TEST_MOTOR_COUNT; j++) {
+                motors[j] = get_motor_pwm(j+1);
+            }
+            print_motor_values(motors, TEST_MOTOR_COUNT, "    Motors");
+        }
+    }
+    
+    delay_ms(1000);
+    
+    // 测试中油门
+    printf("Mid throttle (1500):\n");
+    pid_thr = 1500.0f;
+    for (int i = 0; i < 25; i++) {
+        unlocked_motor_output();
+        delay_ms(20);
+        if (i % 10 == 0) {
+            uint16_t motors[4];
+            for (int j = 0; j < TEST_MOTOR_COUNT; j++) {
+                motors[j] = get_motor_pwm(j+1);
+            }
+            print_motor_values(motors, TEST_MOTOR_COUNT, "    Motors");
+        }
+    }
+    
+    delay_ms(1000);
+    
+    // 测试高油门
+    printf("High throttle (1800):\n");
+    pid_thr = 1800.0f;
+    for (int i = 0; i < 25; i++) {
+        unlocked_motor_output();
+        delay_ms(20);
+        if (i % 10 == 0) {
+            uint16_t motors[4];
+            for (int j = 0; j < TEST_MOTOR_COUNT; j++) {
+                motors[j] = get_motor_pwm(j+1);
+            }
+            print_motor_values(motors, TEST_MOTOR_COUNT, "    Motors");
+        }
+    }
+    
+    printf("Throttle response test completed\n");
+}
+
+/**
+ * @brief 测试7: 饱和保护测试
+ * @note 测试当电机输出达到极限时的饱和保护机制
+ */
+void test_motor_saturation_protection(void)
+{
+    printf("\n=== Test 7: Saturation Protection Test ===\n");
+    
+    extern float pid_roll, pid_pitch, pid_yaw, pid_thr;
+    
+    thr_lock_status = UNLOCKED;
+    ground_air_status = IN_AIR;
+    
+    // 设置高油门和大横滚,触发饱和
+    printf("Testing saturation (high throttle + large roll):\n");
+    pid_thr = 1900.0f;
+    pid_roll = 300.0f;
+    pid_pitch = 0.0f;
+    pid_yaw = 0.0f;
+    
+    for (int i = 0; i < 50; i++) {
+        unlocked_motor_output();
+        delay_ms(20);
+        
+        if (i % 10 == 0) {
+            uint16_t motors[4];
+            for (int j = 0; j < TEST_MOTOR_COUNT; j++) {
+                motors[j] = get_motor_pwm(j+1);
+            }
+            print_motor_values(motors, TEST_MOTOR_COUNT, "    Motors");
+            printf("    Yaw restricted: %d\n", MotorOutput_GetYawRestrictionStatus());
+        }
+    }
+    
+    printf("Saturation protection test completed\n");
+}
+
+/**
+ * @brief 测试8: 电机平滑输出测试
+ */
+void test_motor_smoothing(void)
+{
+    printf("\n=== Test 8: Motor Smoothing Test ===\n");
+    
+    extern float pid_roll, pid_pitch, pid_yaw, pid_thr;
+    
+    thr_lock_status = UNLOCKED;
+    ground_air_status = ON_GROUND;  // 地面状态启用平滑
+    
+    printf("Testing motor output smoothing (ground mode):\n");
+    
+    // 突然改变PID值,观察平滑效果
+    pid_roll = 0.0f;
+    pid_pitch = 0.0f;
+    pid_yaw = 0.0f;
+    pid_thr = 1500.0f;
+    
+    for (int i = 0; i < 30; i++) {
+        unlocked_motor_output();
+        delay_ms(50);
+        
+        if (i == 10) {
+            printf("  Step change: roll=200\n");
+            pid_roll = 200.0f;
+        }
+        
+        if (i % 5 == 0) {
+            uint16_t motors[4];
+            for (int j = 0; j < TEST_MOTOR_COUNT; j++) {
+                motors[j] = get_motor_pwm(j+1);
+            }
+            print_motor_values(motors, TEST_MOTOR_COUNT, "    Motors");
+        }
+    }
+    
+    printf("Motor smoothing test completed\n");
+}
+
+//============================================================================
+// 主测试函数
+//============================================================================
+
+/**
+ * @brief 运行完整的电机测试
+ */
+void run_motor_output_test(void)
+{
+    printf("\n");
+    printf("╔═══════════════════════════════════════════════════════════╗\n");
+    printf("║           Quadcopter Motor Output Test Suite             ║\n");
+    printf("╚═══════════════════════════════════════════════════════════╝\n");
+    
+    // 初始化
+    motor_output_initial();
+    board_delay_ms(100);
+    
+    printf("\nMotor output initialized\n");
+    printf("Motor count: %d\n", conf_par.jixing / 10);
+    printf("Idle speed: %d us\n", Min_PWM_Out);
+    printf("Max PWM: %d us\n", Max_PWM_Out);
+    
+    g_data_index = 0;
+    g_test_running = true;
+    
+    // 运行测试
+    test_motor_idle_output();
+    board_delay_ms(1000);
+    
+    test_motor_hover_mix();
+    board_delay_ms(1000);
+    
+    test_motor_roll_response();
+    board_delay_ms(1000);
+    
+    test_motor_pitch_response();
+    board_delay_ms(1000);
+    
+    test_motor_yaw_response();
+    board_delay_ms(1000);
+    
+    test_motor_throttle_response();
+    board_delay_ms(1000);
+    
+    test_motor_saturation_protection();
+    board_delay_ms(1000);
+    
+    test_motor_smoothing();
+    
+    // 打印总结
+    print_test_summary();
+    
+    // 恢复安全状态
+    thr_lock_status = LOCKED;
+    locked_motor_output();
+    
+    printf("\nAll tests completed!\n");
+    g_test_running = false;
+}
+
+/**
+ * @brief 简单的单步测试
+ * @param step 测试步骤: 1-怠速, 2-悬停, 3-横滚, 4-俯仰, 5-偏航
+ */
+void run_motor_simple_test(uint8_t step)
+{
+    extern float pid_roll, pid_pitch, pid_yaw, pid_thr;
+    
+    motor_output_initial();
+    board_delay_ms(100);
+    
+    switch(step) {
+        case 1:
+            printf("Idle test\n");
+            thr_lock_status = LOCKED;
+            for (int i = 0; i < 100; i++) {
+                locked_motor_output();
+                board_delay_ms(10);
+            }
+            break;
+            
+        case 2:
+            printf("Hover test\n");
+            thr_lock_status = UNLOCKED;
+            ground_air_status = IN_AIR;
+            pid_roll = 0; pid_pitch = 0; pid_yaw = 0; pid_thr = 1500;
+            for (int i = 0; i < 100; i++) {
+                unlocked_motor_output();
+                board_delay_ms(10);
+            }
+            break;
+            
+        case 3:
+            printf("Roll test\n");
+            thr_lock_status = UNLOCKED;
+            ground_air_status = IN_AIR;
+            pid_roll = 100; pid_pitch = 0; pid_yaw = 0; pid_thr = 1500;
+            for (int i = 0; i < 100; i++) {
+                unlocked_motor_output();
+                board_delay_ms(10);
+            }
+            break;
+            
+        case 4:
+            printf("Pitch test\n");
+            thr_lock_status = UNLOCKED;
+            ground_air_status = IN_AIR;
+            pid_roll = 0; pid_pitch = 100; pid_yaw = 0; pid_thr = 1500;
+            for (int i = 0; i < 100; i++) {
+                unlocked_motor_output();
+                board_delay_ms(10);
+            }
+            break;
+            
+        case 5:
+            printf("Yaw test\n");
+            thr_lock_status = UNLOCKED;
+            ground_air_status = IN_AIR;
+            pid_roll = 0; pid_pitch = 0; pid_yaw = 100; pid_thr = 1500;
+            for (int i = 0; i < 100; i++) {
+                unlocked_motor_output();
+                board_delay_ms(10);
+            }
+            break;
+            
+        default:
+            printf("Invalid test step\n");
+            break;
+    }
+    
+    // 恢复锁定
+    thr_lock_status = LOCKED;
+    locked_motor_output();
+    
+    printf("Test completed\n");
+}
+#endif

+ 1 - 1
controller_yy_app/software/soft_port_uart4.c

@@ -12,7 +12,7 @@
 #include "soft_usharpradar.h"
 #include "string.h"
 #include "ver_config.h"
-
+// 硬件未链接
 struct _uart_device *payload_uart = NULL;
 
 // 选择串口 4 设备

+ 4 - 3
controller_yy_app/software/soft_sdcard.c

@@ -34,7 +34,7 @@ WriteBuffer字节  写入速度    写固定字节数             写大数据
  *                              定义变量
  ******************************************************************************
  */
-#if 1
+
 FATFS fs;                /* FatFs文件系统对象 */
 FIL fnew_data, fnew_log; /* 文件对象 */
 FRESULT res_sd;          /* 文件操作结果 */
@@ -274,7 +274,7 @@ void sdcard_inital(uint8_t init_type)
     _sd_init_ok = 1;
     printf("SD card initialization completed!\n");
 }
-#endif
+
 #ifdef SOFT_SD_TEST
 // 测试代码 - 注意:这里不再重复包含头文件,因为上面已经包含了
 
@@ -713,11 +713,12 @@ int sd_write_data(const char *filename, const uint8_t *data, uint32_t size)
     f_close(&file);
     return 0;
 }
+
 #include "hard_system_delay.h"
 /**
  * @brief 测试主函数
  */
-void main_test_demo(void)
+void sd_test_demo(void)
 {
     // 先初始化SD卡
     sdcard_inital(0);

+ 157 - 1
controller_yy_app/software/soft_system.c

@@ -2,7 +2,7 @@
 
 #include "hard_system.h"
 #include "soft_system.h"
-
+#include "test.h"
 
 void system_reset(void)
 {
@@ -15,3 +15,159 @@ void close_imu_dma(void)
     u3_dma_disable(); // 实际dma通道未使用 使用串口fifo中断替代了 实在要用dma 需要触发io物理接在串口接收io 消耗定时器的2路通道 软件模拟空闲中断
 }
 
+#ifdef SOFT_SYSTEM_TEST
+//============================================================================
+// 测试函数
+//============================================================================
+
+/**
+ * @brief 测试系统复位功能
+ * @note 此函数会触发系统复位,执行后程序会重启
+ */
+void test_system_reset(void)
+{
+    printf("\n=== Test: System Reset ===\n");
+    printf("System will reset in 3 seconds...\n");
+    printf("Press any key to cancel, or wait for reset\n");
+    
+    // 延时等待,让用户有机会看到消息
+    for (int i = 3; i > 0; i--) {
+        printf("  %d...\n", i);
+        for (volatile int j = 0; j < 1000000; j++);  // 简单延时
+    }
+    
+    printf("Resetting system now...\n");
+    system_reset();
+    
+    // 正常情况下不会执行到这里
+    printf("[FAIL] System reset failed\n");
+}
+
+/**
+ * @brief 测试关闭IMU DMA功能
+ */
+void test_close_imu_dma(void)
+{
+    printf("\n=== Test: Close IMU DMA ===\n");
+    
+    printf("Calling close_imu_dma()...\n");
+    close_imu_dma();
+    printf("IMU DMA disabled\n");
+    
+    printf("[PASS] Close IMU DMA test\n");
+}
+
+/**
+ * @brief 模拟测试(不实际复位,只打印信息)
+ */
+void test_system_reset_simulate(void)
+{
+    printf("\n=== Test: System Reset Simulation ===\n");
+    printf("Simulating system reset (no actual reset)\n");
+    printf("  - Saving system state...\n");
+    printf("  - Flushing caches...\n");
+    printf("  - Resetting peripherals...\n");
+    printf("  - Restarting system...\n");
+    
+    printf("[PASS] Reset simulation (no actual reset)\n");
+}
+
+//============================================================================
+// 主测试函数
+//============================================================================
+
+/**
+ * @brief 运行所有系统接口测试(不包含实际复位)
+ */
+void run_system_test(void)
+{
+    printf("\n");
+    printf("========================================\n");
+    printf("    System Interface Test Suite\n");
+    printf("========================================\n");
+    
+    // 测试关闭DMA(不会影响系统运行)
+    test_close_imu_dma();
+    
+    // 模拟复位测试(不实际复位)
+    test_system_reset_simulate();
+    
+    printf("\n========================================\n");
+    printf("    All tests completed\n");
+    printf("========================================\n");
+}
+
+/**
+ * @brief 运行包含实际复位的测试(谨慎使用)
+ * @param delay_seconds 复位前延时秒数
+ */
+void run_system_test_with_reset(uint32_t delay_seconds)
+{
+    printf("\n");
+    printf("========================================\n");
+    printf("    System Interface Test (with Reset)\n");
+    printf("========================================\n");
+    
+    test_close_imu_dma();
+    
+    printf("\n");
+    printf("!!! WARNING: System will reset !!!\n");
+    printf("Delay: %u seconds\n", delay_seconds);
+    
+    if (delay_seconds > 0) {
+        for (uint32_t i = delay_seconds; i > 0; i--) {
+            printf("  %u...\n", i);
+            for (volatile uint32_t j = 0; j < 1000000; j++);
+        }
+    }
+    
+    test_system_reset();
+}
+
+//============================================================================
+// 菜单测试
+//============================================================================
+
+/**
+ * @brief 交互式测试菜单
+ */
+void run_system_test_menu(void)
+{
+    printf("\n");
+    printf("========================================\n");
+    printf("    System Test Menu\n");
+    printf("========================================\n");
+    printf("1 - Test close_imu_dma()\n");
+    printf("2 - Test system_reset() simulate (no reset)\n");
+    printf("3 - Test system_reset() with 3s delay (actual reset)\n");
+    printf("4 - Run all safe tests\n");
+    printf("q - Exit\n");
+    printf("========================================\n");
+    
+    // 这里需要用户输入,如果没有输入处理,可以只打印菜单
+    printf("Please select an option in your main loop\n");
+}
+
+//============================================================================
+// 快速测试
+//============================================================================
+
+/**
+ * @brief 快速测试(仅测试安全接口)
+ */
+void run_system_quick_test(void)
+{
+    printf("\n=== Quick System Test ===\n");
+    
+    printf("Testing close_imu_dma()...\n");
+    close_imu_dma();
+    printf("  - IMU DMA closed\n");
+    
+    printf("\nSystem interfaces available:\n");
+    printf("  - system_reset()     : Reset the system\n");
+    printf("  - close_imu_dma()    : Disable IMU DMA\n");
+    
+    printf("\nQuick test completed\n");
+}
+
+#endif

+ 194 - 0
controller_yy_app/software/soft_time.c

@@ -2,6 +2,7 @@
 #include "hard_system_time.h"
 
 #include "soft_time.h"
+#include "test.h"
 
 //系统时间定时器初始化
 void system_time_initial(void) { system_time_init(); }
@@ -34,3 +35,196 @@ micros() - system_time = 200000233.
 */
 //试图解决32位定时器只能计时72分钟,用64位的变量来累计计时
 void time_hookfunction(void) {}
+
+
+#ifdef SOFT_TIMER_TEST
+
+
+//============================================================================
+// 测试函数
+//============================================================================
+
+/**
+ * @brief 测试系统时间初始化
+ */
+void test_time_init(void)
+{
+    printf("\n=== Test: System Time Init ===\n");
+    
+    system_time_initial();
+    printf("System time initialized\n");
+    
+    uint32_t time = micros();
+    printf("Current time: %u us\n", time);
+    
+    if (time > 0) {
+        printf("[PASS] Time init test\n");
+    } else {
+        printf("[FAIL] Time init test\n");
+    }
+}
+
+/**
+ * @brief 测试 micros() 函数
+ */
+void test_micros(void)
+{
+    printf("\n=== Test: micros() Function ===\n");
+    
+    uint32_t t1 = micros();
+    printf("Time 1: %u us\n", t1);
+    
+    // 简单延时
+    for (volatile int i = 0; i < 10000; i++);
+    
+    uint32_t t2 = micros();
+    printf("Time 2: %u us\n", t2);
+    printf("Delta: %u us\n", t2 - t1);
+    
+    if (t2 > t1) {
+        printf("[PASS] micros() test\n");
+    } else {
+        printf("[FAIL] micros() test\n");
+    }
+}
+
+/**
+ * @brief 测试 time_interval() 函数
+ */
+void test_time_interval(void)
+{
+    printf("\n=== Test: time_interval() Function ===\n");
+    
+    uint32_t last_time = micros();
+    printf("Last time: %u us\n", last_time);
+    
+    // 延时一段时间
+    for (volatile int i = 0; i < 50000; i++);
+    
+    uint32_t cur_time = micros();
+    printf("Current time: %u us\n", cur_time);
+    
+    uint32_t interval = time_interval(cur_time, &last_time);
+    printf("Interval: %u us\n", interval);
+    printf("New last time: %u us\n", last_time);
+    
+    if (interval > 0) {
+        printf("[PASS] time_interval() test\n");
+    } else {
+        printf("[FAIL] time_interval() test\n");
+    }
+}
+
+/**
+ * @brief 测试 time_interval() 溢出处理
+ */
+void test_time_interval_overflow(void)
+{
+    printf("\n=== Test: time_interval() Overflow Handling ===\n");
+    
+    // 模拟溢出情况
+    uint32_t last_time = 0xFFFFFFF0;  // 接近最大值
+    uint32_t cur_time = 100;           // 溢出后的值
+    
+    printf("Simulate: last=0x%X, cur=0x%X\n", last_time, cur_time);
+    
+    uint32_t interval = time_interval(cur_time, &last_time);
+    printf("Interval: %u us\n", interval);
+    printf("New last time: %u us\n", last_time);
+    
+    if (interval == 2500) {  // ERR_DT
+        printf("[PASS] Overflow handling test\n");
+    } else {
+        printf("[FAIL] Overflow handling test (expected 2500)\n");
+    }
+}
+
+/**
+ * @brief 连续时间采集测试
+ */
+void test_time_continuous(void)
+{
+    printf("\n=== Test: Continuous Time Collection ===\n");
+    
+    uint32_t last_time = micros();
+    printf("Start time: %u us\n", last_time);
+    
+    for (int i = 0; i < 10; i++) {
+        // 简单延时
+        for (volatile int j = 0; j < 10000; j++);
+        
+        uint32_t cur_time = micros();
+        uint32_t interval = time_interval(cur_time, &last_time);
+        
+        printf("  Sample %d: interval=%u us\n", i+1, interval);
+    }
+    
+    printf("[PASS] Continuous collection test\n");
+}
+
+/**
+ * @brief 测试 time_hookfunction()
+ */
+void test_time_hook(void)
+{
+    printf("\n=== Test: time_hookfunction() ===\n");
+    
+    printf("Calling time_hookfunction()...\n");
+    time_hookfunction();
+    printf("time_hookfunction() executed\n");
+    
+    printf("[PASS] Hook function test\n");
+}
+
+//============================================================================
+// 主测试函数
+//============================================================================
+
+/**
+ * @brief 运行所有时间接口测试
+ */
+void run_time_test(void)
+{
+    printf("\n");
+    printf("========================================\n");
+    printf("    System Time Interface Test\n");
+    printf("========================================\n");
+    
+    test_time_init();
+    test_micros();
+    test_time_interval();
+    test_time_interval_overflow();
+    test_time_continuous();
+    test_time_hook();
+    
+    printf("\n========================================\n");
+    printf("    All tests completed\n");
+    printf("========================================\n");
+}
+
+/**
+ * @brief 快速测试(只测试基本功能)
+ */
+void run_time_quick_test(void)
+{
+    printf("\n=== Quick Time Test ===\n");
+    
+    system_time_initial();
+    
+    uint32_t start = micros();
+    printf("Start: %u us\n", start);
+    
+    for (volatile int i = 0; i < 50000; i++);
+    
+    uint32_t end = micros();
+    printf("End: %u us\n", end);
+    printf("Elapsed: %u us\n", end - start);
+    
+    uint32_t last = start;
+    uint32_t interval = time_interval(end, &last);
+    printf("Interval via function: %u us\n", interval);
+    
+    printf("Quick test done\n");
+}
+
+#endif

+ 45 - 8
controller_yy_app/software/soft_voltage.c

@@ -4,7 +4,7 @@
 #include "params.h"
 #include "string.h"
 #include "ver_config.h"
-
+#include "test.h"
 static VoltageBms _voltage_bms = {.link_status = COMP_NOEXIST};
 
 /**
@@ -13,7 +13,8 @@ static VoltageBms _voltage_bms = {.link_status = COMP_NOEXIST};
  */
 void Voltage_Init(void)
 {
-    if (ver_par.hardware_id == HW_V8M_YY)
+   
+   // if (ver_par.hardware_id == HW_V8M_YY)
     {
         V8M_YY_ADC1_Init();
     }
@@ -28,9 +29,9 @@ float Voltage_GetVolt(VoltageCHType VoltCH)
 {
     float validVolt = 0.0f;
     /* 根据是哪个硬件选择电压接口 */
-    switch (ver_par.hardware_id)
+   // switch (ver_par.hardware_id)
     {    
-    case HW_V8M_YY:
+   // case HW_V8M_YY:
         switch (VoltCH)
         {
         case Volt_MC_CH:
@@ -68,10 +69,10 @@ float Voltage_GetVolt(VoltageCHType VoltCH)
                         parinf._par_volt_offset_b[1] / 10.0f;
             break;
         }
-        break;
+       // break;
 
-    default:
-        break;
+   // default:
+        //break;
     }
     return validVolt;
 }
@@ -82,7 +83,7 @@ float Voltage_GetVolt(VoltageCHType VoltCH)
  */
 void Voltage_Update(void)
 {
-    if (ver_par.hardware_id == HW_V8M_YY)
+    //if (ver_par.hardware_id == HW_V8M_YY)
     {
         V8M_YY_ADC_UpdateVoltage();
     }
@@ -94,3 +95,39 @@ VoltageBms *Voltage_GetBmsInfo(void)
 {
     return &_voltage_bms;
 }
+
+#ifdef SOFT_VOL_TEST
+
+
+static void V8M_YY_Voltage_PrintAllSimple(void)
+{
+    // 通道名称数组
+    const char *channel_names[] = {
+        "MC", "AD1", "AD2", "AD3", "AD4"
+    };
+    
+    printf("=== ADC电压值 ===\n");
+    
+    // 循环打印6个通道
+    for (int i = 0; i < 5; i++) {
+        float voltage = V8M_YY_Voltage_GetVolt(i);
+        printf("通道%d(%s): %.3f V\n", i, channel_names[i], voltage);
+    }
+}
+//============================================================================
+// 测试函数
+//============================================================================
+void soft_vol_test(void)
+{
+  Voltage_Init();
+
+  while(1)
+  {
+      Voltage_Update();
+      V8M_YY_Voltage_PrintAllSimple();
+  }
+ 
+}
+
+
+#endif

+ 32 - 4
controller_yy_app/user_src/inc/test.h

@@ -1,22 +1,50 @@
 #pragma once  // 头文件保护
 
 #define TEST_EN  // 启用测试总开关
-
+#include <stdint.h>
+#include "board.h"
 #ifdef TEST_EN
 // 以下测试模块只在 TEST_EN 定义时才启用
 #define LED_TEST       // LED测试
-#define PWM_TEST       // PWM测试  
+void v8m_yy_led_test(void);
+#define PWM_TEST       // PWM测试 
+void v8m_yy_motor_pwm_test(void); 
 #define ADC_TEST       // ADC测试
+void v8m_yy_adc_test(void);
 #define TIMER0_TEST    // 定时器0测试
+void timer0_test(void);
 #define CPU_DELAY_TEST // CPU延时测试
+void cpu_delay_test(void);
 #define TIMER1_TEST    // 2.5ms定时测试
+void timer1_test(void);
 #define CAN2_TEST      // CAN2 收发测试
+void can2_test(void);
 #define UART3_TEST     // UART3 收发测试
+void imu_uart3_test(void);
 #define SUSTEM_TEST    // 软件复位 测试
+void system_test(void);
 #define UART2_RX_TEST     // SBUS RX 测试
+void uart2_sbus_test(void);
 #define UART2_TX_TEST // SBUS TX 测试
+void sbus_uart2_out_test(void);
 // #define SD_TEST // SD TEST
 #define GD25Q16_TEST  // SPI-FLASH 测试
-#define UART_DRV_TEST 
-#define SOFT_SD_TEST
+void test_gd25q16_quick(void);
+#define UART_DRV_TEST    // 通用串口驱动测试 tx dma rx fifo 中断
+#define SOFT_SD_TEST     // sd卡创建日志目录测试
+void sd_test_demo(void);
+#define FLASH_TEST       // qspi-flash测试
+void run_flash_tests(void);
+#define SOFT_FLASH_TEST  // spi-flash测试
+
+#define SOFT_VOL_TEST   // 电压读取测试
+void soft_vol_test(void);
+#define SOFT_SYSTEM_TEST
+void run_system_test_with_reset(uint32_t delay_seconds);
+#define SOFT_MOTOR_TEST  // 混控器测试
+void run_motor_output_test(void);
+void run_motor_simple_test(uint8_t step);
+#define SOFT_TIMER_TEST
+void run_time_test(void);
+void run_time_quick_test(void);
 #endif

+ 14 - 312
controller_yy_app/user_src/main.c

@@ -4,7 +4,7 @@
  * SPDX-License-Identifier: BSD-3-Clause
  *
  */
-#if 1
+
 #include <stdio.h>
 #include "board.h"
 
@@ -24,6 +24,8 @@
 #include "hard_flash_gd25q16.h"
 #include "drv_usart.h"
 #include "soft_sdcard.h"
+#include "bsp_V8M_flash.h"
+#include "soft_voltage.h"
 #include "main.h"
 #include "hpm_math.h"
 #endif
@@ -56,6 +58,7 @@ uint32_t get_end_time(void)
 }
 float theta ;
 float sin_theta;
+#ifdef TEST_EN
 static void test_hard(void)
 {
     // v8m_yy_led_test();
@@ -64,13 +67,18 @@ static void test_hard(void)
     // timer0_test();
     // cpu_delay_test();
     // timer1_test();
-    // can2_test();
+     can2_test();
     // imu_uart3_test();
     // uart2_sbus_test();
     // system_test();
     // sbus_uart2_out_test();
     // test_gd25q16_quick();
-    main_test_demo();
+    // sd_test_demo();
+    // run_flash_tests();
+    // run_time_test();
+    // run_system_test_with_reset(100);
+    // soft_vol_test();
+
     while(1)
     {
       theta += PI*0.1;
@@ -81,6 +89,7 @@ static void test_hard(void)
     }
      
 }
+#endif
 int main(void)
 {
     board_init();
@@ -91,317 +100,10 @@ int main(void)
    
     //printf("hello world %f\n", i);
     //printf("sin theta is %f\r\n", sin_theta);
-
+#ifdef TEST_EN
     test_hard();
+#endif
     return 0;
 }
 // DMA 最大4k
 
-#endif
-#if 0
-/*
- * Copyright (c) 2021 HPMicro
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
-
-#include "board.h"
-#include "hpm_sdmmc_sd.h"
-#include "ff.h"
-#include "diskio.h"
-
-FATFS s_sd_disk;
-FIL s_file;
-DIR s_dir;
-FRESULT fatfs_result;
-BYTE work[FF_MAX_SS];
-
-const TCHAR driver_num_buf[3] = { DEV_SD + '0', ':', '/' };
-
-#define TEST_DIR_NAME "hpmicro_sd_test_dir0"
-
-void show_menu(void);
-
-const char *show_error_string(FRESULT fresult);
-
-static FRESULT sd_mount_fs(void);
-
-static FRESULT sd_mkfs(void);
-
-static FRESULT sd_write_file(void);
-
-static FRESULT sd_read_file(void);
-
-static FRESULT sd_dir_test(void);
-
-static FRESULT sd_big_file_test(void);
-
-int main(void)
-{
-    bool need_init_filesystem = true;
-    board_init();
-    show_menu();
-
-    while (1) {
-        char option = getchar();
-
-        /* Before doing FATFS operation, ensure the SD card is present */
-        DSTATUS dstatus = disk_status(DEV_SD);
-        printf("sd state is %d\r\n", dstatus); // 找到SD卡
-        if (dstatus == STA_NODISK) {
-            printf("No disk in the SD slot, please insert an SD card...\n");
-            do {
-                dstatus = disk_status(DEV_SD);
-            } while (dstatus == STA_NODISK);
-            board_delay_ms(100);
-            printf("Detected SD card, re-initialize the filesystem...\n");
-            need_init_filesystem = true;
-        }
-        dstatus = disk_initialize(DEV_SD);
-        if (dstatus != RES_OK) {
-            printf("Failed to initialize SD disk\n");
-        }
-        if (need_init_filesystem) {
-            fatfs_result = sd_mount_fs();
-            if (fatfs_result == FR_NO_FILESYSTEM) {
-                printf("There is no File system available, making file system...\n");
-                fatfs_result = sd_mkfs();
-                if (fatfs_result != FR_OK) {
-                    printf("Failed to make filesystem, cause:%s\n", show_error_string(fatfs_result));
-                } else {
-                    need_init_filesystem = false;
-                }
-            }
-        }
-
-        switch (option) {
-        case '1':
-            fatfs_result = sd_mkfs();
-            break;
-        case '2':
-            fatfs_result = sd_write_file();
-            break;
-        case '3':
-            fatfs_result = sd_read_file();
-            break;
-        case '4':
-            fatfs_result = sd_dir_test();
-            break;
-        case 's':
-            fatfs_result = sd_big_file_test();
-            break;
-        default:
-            show_menu();
-            break;
-        }
-    }
-
-}
-
-void show_menu(void)
-{
-    const char menu_str[] = "SD FATFS demo\n-----------------------------------\n"
-                            "1 - Format the SD card with FATFS\n"
-                            "2 - Create hello.txt\n"
-                            "3 - Read 1st line from hello.txt\n"
-                            "4 - Directory related test\n"
-                            "s - Large file write test\n"
-                            "Others - Show menu\n";
-
-    printf(menu_str);
-}
-
-static FRESULT sd_mount_fs(void)
-{
-    FRESULT fresult = f_mount(&s_sd_disk, driver_num_buf, 1);
-    if (fresult == FR_OK) {
-        printf("SD card has been mounted successfully\n");
-    } else {
-        printf("Failed to mount SD card, cause: %s\n", show_error_string(fresult));
-    }
-
-    fresult = f_chdrive(driver_num_buf);
-    return fresult;
-}
-
-static FRESULT sd_mkfs(void)
-{
-    printf("Formatting the SD card, depending on the SD card capacity, the formatting process may take a long time\n");
-    FRESULT fresult = f_mkfs(driver_num_buf, NULL, work, sizeof(work));
-    if (fresult != FR_OK) {
-        printf("Making File system failed, cause: %s\n", show_error_string(fresult));
-    } else {
-        printf("Making file system is successful\n");
-    }
-
-    return fresult;
-}
-
-static FRESULT sd_write_file(void)
-{
-    FRESULT fresult = f_open(&s_file, "readme.txt", FA_WRITE | FA_CREATE_ALWAYS);
-    if (fresult != FR_OK) {
-        printf("Create new file failed, cause: %d\n", show_error_string(fresult));
-    } else {
-        printf("Create new file successfully, status=%d\n", fresult);
-    }
-    char hello_str[] = "Hello, this is SD card FATFS demo\n";
-    UINT byte_written;
-    fresult = f_write(&s_file, hello_str, sizeof(hello_str), &byte_written);
-    if (fresult != FR_OK) {
-        printf("Write file failed, cause: %s\n", show_error_string(fresult));
-    } else {
-        printf("Write file operation is successfully\n");
-    }
-
-    f_close(&s_file);
-
-    return fresult;
-}
-
-static FRESULT sd_read_file(void)
-{
-    FRESULT fresult = f_open(&s_file, "readme.txt", FA_READ);
-    if (fresult != FR_OK) {
-        printf("Open file failed, cause: %s\n", show_error_string(fresult));
-    } else {
-        printf("Open file successfully\n");
-    }
-
-    if (fresult != FR_OK) {
-        return fresult;
-    }
-
-    TCHAR str[100];
-    f_gets(str, sizeof(str), &s_file);
-    printf("%s\n", str);
-
-    f_close(&s_file);
-
-    return fresult;
-}
-
-static FRESULT sd_big_file_test(void)
-{
-    FRESULT fresult = f_open(&s_file, "big_file.bin", FA_WRITE | FA_CREATE_ALWAYS);
-    if (fresult != FR_OK) {
-        printf("Create new file failed, cause: %s\n", show_error_string(fresult));
-    } else {
-        printf("Create new file successfully\n");
-    }
-
-    uint32_t write_size = 1024UL * 1024UL * 100UL;
-    static uint8_t buf[32768];
-    for (uint32_t i = 0; i < sizeof(buf); i++) {
-        buf[i] = i & 0xFF;
-    }
-    while (write_size > 0) {
-        UINT byte_written;
-        fresult = f_write(&s_file, buf, sizeof(buf), &byte_written);
-        if (fresult != FR_OK) {
-            printf("Write file failed, cause: %s\n", show_error_string(fresult));
-            return fresult;
-        }
-
-        write_size -= byte_written;
-    }
-    printf("Write file operation is successful\n");
-
-    f_close(&s_file);
-
-    return fresult;
-}
-
-
-static FRESULT sd_dir_test(void)
-{
-    FRESULT fresult = f_mkdir(TEST_DIR_NAME);
-    if (fresult != FR_OK) {
-        printf("Creating new directory failed, cause: %s\n", show_error_string(fresult));
-    } else {
-        printf("Creating new directory succeeded\n");
-    }
-
-    fresult = f_rmdir(TEST_DIR_NAME);
-    if (fresult != FR_OK) {
-        printf("Removing new directory failed, cause: %s\n", show_error_string(fresult));
-    } else {
-        printf("Removing new directory succeeded\n");
-    }
-
-    return fresult;
-}
-
-const char *show_error_string(FRESULT fresult)
-{
-    const char *result_str;
-
-    switch (fresult) {
-    case FR_OK:
-        result_str = "succeeded";
-        break;
-    case FR_DISK_ERR:
-        result_str = "A hard error occurred in the low level disk I/O level";
-        break;
-    case FR_INT_ERR:
-        result_str = "Assertion failed";
-        break;
-    case FR_NOT_READY:
-        result_str = "The physical drive cannot work";
-        break;
-    case FR_NO_FILE:
-        result_str = "Could not find the file";
-        break;
-    case FR_NO_PATH:
-        result_str = "Could not find the path";
-        break;
-    case FR_INVALID_NAME:
-        result_str = "Tha path name format is invalid";
-        break;
-    case FR_DENIED:
-        result_str = "Access denied due to prohibited access or directory full";
-        break;
-    case FR_EXIST:
-        result_str = "Access denied due to prohibited access";
-        break;
-    case FR_INVALID_OBJECT:
-        result_str = "The file/directory object is invalid";
-        break;
-    case FR_WRITE_PROTECTED:
-        result_str = "The physical drive is write protected";
-        break;
-    case FR_INVALID_DRIVE:
-        result_str = "The logical driver number is invalid";
-        break;
-    case FR_NOT_ENABLED:
-        result_str = "The volume has no work area";
-        break;
-    case FR_NO_FILESYSTEM:
-        result_str = "There is no valid FAT volume";
-        break;
-    case FR_MKFS_ABORTED:
-        result_str = "THe f_mkfs() aborted due to any problem";
-        break;
-    case FR_TIMEOUT:
-        result_str = "Could not get a grant to access the volume within defined period";
-        break;
-    case FR_LOCKED:
-        result_str = "The operation is rejected according to the file sharing policy";
-        break;
-    case FR_NOT_ENOUGH_CORE:
-        result_str = "LFN working buffer could not be allocated";
-        break;
-    case FR_TOO_MANY_OPEN_FILES:
-        result_str = "Number of open files > FF_FS_LOCK";
-        break;
-    case FR_INVALID_PARAMETER:
-        result_str = "Given parameter is invalid";
-        break;
-    default:
-        result_str = "Unknown error";
-        break;
-    }
-    return result_str;
-}
-#endif

+ 259 - 76
controller_yy_app/v8/v8m/bsp_V8M_flash.c

@@ -3,6 +3,7 @@
 #include "hpm_l1c_drv.h"
 #include "hpm_soc.h"
 #include "bsp_V8M_flash.h"
+#include "test.h"
 // 这里要重新安排,程序什么的所有都要写在外部flash里 且有一些字段是芯片定义的不可写入地区,比如
 // __attribute__ ((section(".nor_cfg_option"))) const uint32_t option[4] = {0xfcf90002, 0x00000007, 0xE, 0x0};
 // define region NOR_CFG_OPTION = [ from 0x80000400 size 0x0C00 ];
@@ -10,118 +11,174 @@
 // 这个字段就是narflash 的描述符,不能覆盖 所以程序得后移
 // 从链接字段里可以发现 define region XPI0 = [from 0x80003000 size (_flash_size - 0x3000) ];   /* XPI0 */ 
 // app是从0x80003000开始的 也就是boot只能从这开始
-#if 0
+//#define BOARD_APP_XPI_NOR_XPI_BASE     (HPM_XPI0)
+//#define BOARD_APP_XPI_NOR_CFG_OPT_HDR  (0xfcf90002U) 0xfcf9 - FLASH configuration option tag 2 option words 有效选项为2
+//#define BOARD_APP_XPI_NOR_CFG_OPT_OPT0 (0x00000007U)  7 - 133MHz
+//#define BOARD_APP_XPI_NOR_CFG_OPT_OPT1 (0x0000000EU)
 // 起始地址 0x80000000
 // IAP标志地址 - 选择Flash中一个合适的扇区
-// HPM6750 Flash通常映射在0x80000000开始
-#define IAP_FLAG_ADDR ((uint32_t)0x8000C000)  
+// HPM6750 Flash通常映射在0x80000000开始 程序从64k开始
+// #define IAP_FLAG_ADDR ((uint32_t)0x8000C000)  // 30k的擦除标志地址 
 
+// 后续发现好像可以去掉这些初始化的配置字节???
+#define IAP_FLAG_ADDR ((uint32_t)0x80050000)
 #define IAP_FLAG_NEED_UPDATE ((uint16_t)0xABCD)
 
 // Flash大小配置 - 根据实际Flash芯片修改
 #define FLASH_BASE_ADDR         0x80000000
 #define FLASH_SECTOR_SIZE       0x1000      // 4KB,常见QSPI Flash扇区大小
-#define FLASH_PAGE_SIZE         256         // 编程页大小
 
 // XPI Nor Flash 配置结构体
-static xpi_nor_config_t s_flash_config;
+static xpi_nor_config_t s_xpi_nor_config;
 
 /**
- * @brief 初始化Flash控制器并获取配置
+ * @brief 初始化Flash控制器并获取配置  bootrom在初始化时已经对应的xpi配置字节
  */
+
 static void flash_init(void)
 {
     static bool s_flash_inited = false;
     
-    if (!s_flash_inited) {
-        // 获取Flash配置(从ROM API读取)
-        rom_xpi_nor_get_config(HPM_XPI0, &s_flash_config, NULL);
+    if (!s_flash_inited) { // 是默认配置字节 也可以手动修改xpi的参数
+        xpi_nor_config_option_t option;
+        option.header.U = BOARD_APP_XPI_NOR_CFG_OPT_HDR;
+        option.option0.U = BOARD_APP_XPI_NOR_CFG_OPT_OPT0;
+        option.option1.U = BOARD_APP_XPI_NOR_CFG_OPT_OPT1;
+        
+        disable_global_irq(CSR_MSTATUS_MIE_MASK);
+        hpm_stat_t status = rom_xpi_nor_auto_config(HPM_XPI0, &s_xpi_nor_config, &option);
+        fencei();  // 刷新指令缓存
+        enable_global_irq(CSR_MSTATUS_MIE_MASK);
+        
+        if (status != status_success) {
+            printf("ERROR: Flash init failed\n");
+            while(1);
+        }
         s_flash_inited = true;
     }
 }
 
+
 /**
- * @brief 根据地址计算所在扇区(HPM6750版)
- * 
- * HPM6750的外部Flash扇区划分与具体Flash芯片有关
- * 这里以常见的4KB扇区为例
+ * @brief 根据绝对地址获取扇区起始偏移
+ * @param address 绝对地址
  */
-static uint32_t get_sector_index(uint32_t address)
+static uint32_t get_sector_start_offset(uint32_t address)
 {
-    // 计算相对于Flash基址的偏移
     uint32_t offset = address - FLASH_BASE_ADDR;
-    
-    // 扇区索引 = 偏移 / 扇区大小
-    return offset / FLASH_SECTOR_SIZE;
+    return (offset / FLASH_SECTOR_SIZE) * FLASH_SECTOR_SIZE;
 }
-
 /**
- * @brief 擦除包含指定地址的扇区
+ * @brief 编程半字(2字节)到Flash
  */
-static void flash_erase_sector(uint32_t address)
+static void flash_program_halfword(uint32_t address, uint16_t data)
 {
     flash_init();
     
-    // HPM6750需要先禁用缓存,因为我们在擦除Flash
-    l1c_dc_invalidate_all();
+    uint32_t sector_start_offset = get_sector_start_offset(address);
+    uint32_t offset_in_sector = (address - FLASH_BASE_ADDR) - sector_start_offset;
     
-    // 确保地址对齐到扇区边界
-    uint32_t sector_start = address & ~(FLASH_SECTOR_SIZE - 1);
+    printf("Programming: addr=0x%x, sector=0x%x, offset=%d, data=0x%04x\n", 
+           address, sector_start_offset, offset_in_sector, data);
     
-    // 调用ROM API擦除扇区
-    rom_xpi_nor_erase_sector(HPM_XPI0, &s_flash_config, sector_start);
+    static uint8_t sector_buffer[FLASH_SECTOR_SIZE];
+    hpm_stat_t status;
     
-    // 擦除后清理缓存
-    l1c_dc_invalidate_all();
-}
-
-/**
- * @brief 编程半字(2字节)到Flash
- */
-static void flash_program_halfword(uint32_t address, uint16_t data)
-{
-    flash_init();
+    disable_global_irq(CSR_MSTATUS_MIE_MASK);
     
-    // 准备要写入的数据(需要是32位对齐)
-    uint32_t prog_data[2];
-    prog_data[0] = (uint32_t)data;  // 低16位有效
+    // 1. 读取整个扇区
+    status = rom_xpi_nor_read(HPM_XPI0,
+                              xpi_xfer_channel_auto,
+                              &s_xpi_nor_config,
+                              (uint32_t *)sector_buffer,
+                              sector_start_offset,
+                              FLASH_SECTOR_SIZE);
+    if (status != status_success) {
+        enable_global_irq(CSR_MSTATUS_MIE_MASK);
+        printf("ERROR: read sector failed\n");
+        return;
+    }
+    
+    // 2. 读取当前值(按小端序解析)
+    uint16_t current_value = sector_buffer[offset_in_sector] | 
+                             (sector_buffer[offset_in_sector + 1] << 8);
     
-    // HPM6750要求编程地址对齐到编程单元
-    // 这里我们读取整个页,修改后再写回
-    uint8_t page_buffer[FLASH_PAGE_SIZE] __attribute__((aligned(4)));
+    printf("Current value: 0x%04X\n", current_value);
     
-    // 计算页起始地址
-    uint32_t page_start = address & ~(FLASH_PAGE_SIZE - 1);
-    uint32_t offset_in_page = address - page_start;
+    // 3. 检查是否需要更新(使用小端序比较)
+    if (current_value == data) {
+        enable_global_irq(CSR_MSTATUS_MIE_MASK);
+        printf("Data unchanged, skip\n");
+        return;
+    }
     
-    // 先读取整个页
-    rom_xpi_nor_read(HPM_XPI0, &s_flash_config, page_start, page_buffer, FLASH_PAGE_SIZE);
+    // 4. 准备新数据(小端序存储)
+    sector_buffer[offset_in_sector] = data & 0xFF;        // 低字节
+    sector_buffer[offset_in_sector + 1] = (data >> 8) & 0xFF;  // 高字节
     
-    // 修改目标位置
-    *(uint16_t*)(page_buffer + offset_in_page) = data;
+    // 5. 擦除扇区
+    status = rom_xpi_nor_erase_sector(HPM_XPI0,
+                                      xpi_xfer_channel_auto,
+                                      &s_xpi_nor_config,
+                                      sector_start_offset);
+    if (status != status_success) {
+        enable_global_irq(CSR_MSTATUS_MIE_MASK);
+        printf("ERROR: erase failed\n");
+        return;
+    }
     
-    // 擦除整个页所在的扇区
-    flash_erase_sector(address);
+    // 6. 写回整个扇区
+    status = rom_xpi_nor_program(HPM_XPI0,
+                                 xpi_xfer_channel_auto,
+                                 &s_xpi_nor_config,
+                                 (uint32_t *)sector_buffer,
+                                 sector_start_offset,
+                                 FLASH_SECTOR_SIZE);
     
-    // 重新编程整个页
-    rom_xpi_nor_program(HPM_XPI0, &s_flash_config, page_start, page_buffer, FLASH_PAGE_SIZE);
+    fencei();
+    enable_global_irq(CSR_MSTATUS_MIE_MASK);
     
-    // 清理缓存
-    l1c_dc_invalidate_all();
+    if (status != status_success) {
+        printf("ERROR: program failed: %ld\n", status);
+    } else {
+        printf("Halfword written successfully\n");
+    }
 }
 
-/**
- * @brief 从Flash读取N个字节
- */
+
 int hpm_flash_read_nbytes(uint32_t read_addr, uint8_t *read_buf, int32_t read_num)
 {
     flash_init();
     
-    // HPM6750可以直接通过内存映射读取
-    // 但需要确保缓存一致性
-    l1c_dc_invalidate((uint32_t)read_addr, read_num);
+    // 参数检查
+    if (read_buf == NULL || read_num <= 0) {
+        printf("ERROR: invalid parameters\n");
+        return -1;
+    }
+    
+    // 转换为偏移地址
+    uint32_t offset = read_addr - FLASH_BASE_ADDR;
+    
+    // 地址范围检查
+    uint32_t flash_size;
+    rom_xpi_nor_get_property(HPM_XPI0, &s_xpi_nor_config, 
+                             xpi_nor_property_total_size, &flash_size);
+    if (offset + read_num > flash_size) {
+        printf("ERROR: address out of range\n");
+        return -1;
+    }
+    
+    hpm_stat_t  status = rom_xpi_nor_read(HPM_XPI0,
+                              xpi_xfer_channel_auto,
+                              &s_xpi_nor_config,
+                              (uint32_t *)read_buf,  
+                              offset,
+                              read_num);
     
-    memcpy(read_buf, (void*)read_addr, read_num);
+    if (status != status_success) {
+        printf("ERROR: flash read failed at offset 0x%x\n", offset);
+        return -1;
+    }
     
     return read_num;
 }
@@ -131,16 +188,13 @@ int hpm_flash_read_nbytes(uint32_t read_addr, uint8_t *read_buf, int32_t read_nu
  */
 void hpm_clear_iap_flag(void)
 {
-   uint32_t mask;
     
-    // 保存当前中断状态并关闭所有中断
-    mask = disable_global_irq(CSR_MSTATUS_MIE_MASK);
+    disable_global_irq(CSR_MSTATUS_MIE_MASK);
     
     // 写入0xFFFF表示无升级标志
     flash_program_halfword(IAP_FLAG_ADDR, 0xFFFF);
     
-     // 恢复中断状态
-    restore_global_irq(mask);
+    enable_global_irq(CSR_MSTATUS_MIE_MASK);
 }
 
 /**
@@ -148,15 +202,11 @@ void hpm_clear_iap_flag(void)
  */
 void hpm_record_iap_flag(void)
 {
-    uint32_t mask;
-    
-    // 保存当前中断状态并关闭所有中断
-    mask = disable_global_irq(CSR_MSTATUS_MIE_MASK);
+    disable_global_irq(CSR_MSTATUS_MIE_MASK);
     
     flash_program_halfword(IAP_FLAG_ADDR, IAP_FLAG_NEED_UPDATE);
     
-    // 恢复中断状态
-    restore_global_irq(mask);
+    enable_global_irq(CSR_MSTATUS_MIE_MASK);
 }
 
 /**
@@ -172,8 +222,141 @@ void hpm_check_iap_flag(void)
     // 如果需要升级,清除标志
     if (iap_flag == IAP_FLAG_NEED_UPDATE) {
         hpm_clear_iap_flag();
-        // 这里可以触发跳转到Bootloader的逻辑
-        // printf("IAP flag detected, jumping to bootloader...\n");
+       
+    }
+}
+
+#ifdef FLASH_TEST
+// 20250324 test pass
+
+/**
+ * @brief 简单快速测试(只测试一次写入和读取)
+ */
+int test_flash_simple(void)
+{
+    uint16_t test_value = 0xABCD;
+    uint16_t read_value = 0;
+    
+    printf("\nSimple Flash Test\n");
+    printf("Write address: 0x%08X\n", IAP_FLAG_ADDR);
+    printf("Write value: 0x%04X\n", test_value);
+    
+    // 写入
+    printf("Writing... ");
+    flash_program_halfword(IAP_FLAG_ADDR, test_value);
+    // flash_program_halfword(IAP_FLAG_ADDR+2, 0xCDAB);
+    board_delay_ms(10);
+    printf("Done\n");
+  
+    // 读取
+    printf("Reading... ");
+    int ret = hpm_flash_read_nbytes(IAP_FLAG_ADDR, (uint8_t*)&read_value, sizeof(read_value));
+    if (ret != sizeof(read_value)) {
+        printf("Failed\n");
+        return -1;
+    }
+    printf("Read: 0x%04X\n", read_value);
+    
+    // 验证
+    if (read_value == test_value) {
+        printf("Result: PASSED\n");
+        return 0;
+    } else {
+        printf("Result: FAILED (expected 0x%04X, got 0x%04X)\n", test_value, read_value);
+        return -1;
+    }
+}
+
+/**
+ * @brief 测试 IAP 标志功能
+ */
+int test_iap_flag(void)
+{
+    printf("\nIAP Flag Test\n");
+    printf("========================================\n");
+    
+    // 1. 清除标志
+    printf("1. Clearing flag...\n");
+    hpm_clear_iap_flag();
+    board_delay_ms(10);
+    
+    // 2. 检查标志(应该没有升级标志)
+    printf("2. Checking flag (should be no update)...\n");
+    uint16_t flag;
+    hpm_flash_read_nbytes(IAP_FLAG_ADDR, (uint8_t*)&flag, sizeof(flag));
+    printf("   Flag value: 0x%04X\n", flag);
+    
+    if (flag != 0xFFFF) {
+        printf("   ERROR: Flag should be 0xFFFF\n");
+        return -1;
+    }
+    printf("   PASS\n");
+    
+    // 3. 记录升级标志
+    printf("3. Setting update flag...\n");
+    hpm_record_iap_flag();
+    board_delay_ms(10);
+    
+    // 4. 检查标志(应该为 0xABCD)
+    printf("4. Checking flag (should be update needed)...\n");
+    hpm_flash_read_nbytes(IAP_FLAG_ADDR, (uint8_t*)&flag, sizeof(flag));
+    printf("   Flag value: 0x%04X\n", flag);
+    
+    if (flag != IAP_FLAG_NEED_UPDATE) {
+        printf("   ERROR: Flag should be 0x%04X\n", IAP_FLAG_NEED_UPDATE);
+        return -1;
+    }
+    printf("   PASS\n");
+    
+    // 5. 检查并清除标志
+    printf("5. Checking and clearing flag...\n");
+    hpm_check_iap_flag();
+    board_delay_ms(10);
+    
+    // 6. 验证已清除
+    printf("6. Verifying flag cleared...\n");
+    hpm_flash_read_nbytes(IAP_FLAG_ADDR, (uint8_t*)&flag, sizeof(flag));
+    printf("   Flag value: 0x%04X\n", flag);
+    
+    if (flag != 0xFFFF) {
+        printf("   ERROR: Flag should be 0xFFFF\n");
+        return -1;
+    }
+    printf("   PASS\n");
+    
+    printf("========================================\n");
+    printf("IAP Flag Test PASSED\n");
+    
+    return 0;
+}
+
+/**
+ * @brief 主测试函数,可选择运行全部测试或单个测试
+ */
+void run_flash_tests(void)
+{
+    printf("\n");
+    printf("╔══════════════════════════════════════════════════════╗\n");
+    printf("║         HPM6750 Flash Read/Write Test Suite          ║\n");
+    printf("╚══════════════════════════════════════════════════════╝\n");
+   
+    // 先运行简单测试
+    if (test_flash_simple() != 0) {
+        printf("\nSimple test failed! Aborting...\n");
+        return;
+    }
+    
+    printf("\n");
+    
+    // 运行 IAP 标志测试
+    if (test_iap_flag() != 0) {
+        printf("\nIAP flag test failed!\n");
+        return;
     }
+    
+    printf("\n");
+    
 }
+
+
 #endif

+ 1 - 0
controller_yy_app/v8/v8m/bsp_V8M_flash.h

@@ -9,4 +9,5 @@ void V8M_clear_iap_flag(void);
 
 void V8M_record_iap_flag(void);
 
+
 #endif

+ 26 - 22
controller_yy_app/v8/v8m_yy/bsp_V8M_YY_adc.c

@@ -29,7 +29,7 @@ static const float vref_voltage = 3.30f;  /* HPM6750没有内部VREF电压 */
 #define ADC12_CHANEL_5 7
 #define ADC12_CHANEL_6  // 没有内置vref
 
-/* ADC通道定义 */
+/* ADC通道定义 通道定义一定是字节*/
 static uint8_t adc_channels[AD_CHANNEL_NUM] = {
     ADC12_CHANEL_1,   /* 通道1: (飞控供电通道) */
     ADC12_CHANEL_2,   /* 通道2: (AD1INPUT) */
@@ -191,28 +191,32 @@ static void init_sequence_config(void)
 void V8M_YY_ADC1_Init(void)
 {
     /* 1.  IO、时钟配置*/
-
-    HPM_ADC0_IO_0_5_config();
-
-    /* Configure the ADC clock from AHB (@200MHz by default)*/
-
-    clock_set_adc_source(clock_adc0, clk_adc_src_ahb0);
-    /* 2. 通用配置*/
-    if(init_common_config(adc12_conv_mode_sequence) != status_success)
-    {
-      printf("adc12 common config error\r\n");
-    }
-    /* 3. 序列 DMA配置*/
-    init_sequence_config();
-    board_delay_ms(20);
-    /* 4. 启动转换 */
-    if(adc12_trigger_seq_by_sw(ADC12) != status_success)
-    {
-      printf("seq soft trig fail\r\n");
-
-    }
+    static bool adc_is_init = false;
+    if(!adc_is_init)
+    { 
+       HPM_ADC0_IO_0_5_config();
+
+      /* Configure the ADC clock from AHB (@200MHz by default)*/
+
+      clock_set_adc_source(clock_adc0, clk_adc_src_ahb0);
+      /* 2. 通用配置*/
+      if(init_common_config(adc12_conv_mode_sequence) != status_success)
+      {
+        printf("adc12 common config error\r\n");
+      }
+      /* 3. 序列 DMA配置*/
+      init_sequence_config();
+      board_delay_ms(20);
+      /* 4. 启动转换 */
+      if(adc12_trigger_seq_by_sw(ADC12) != status_success)
+      {
+        printf("seq soft trig fail\r\n");
+
+      }
     
-    printf("ADC初始化完成\n");
+      printf("ADC初始化完成\n");
+    }
+   
 }
 /**
  * 更新电压值 - 从DMA缓冲区读取并计算

+ 0 - 2
controller_yy_app/v8/v8m_yy/bsp_V8M_YY_adc.h

@@ -19,7 +19,5 @@ void V8M_YY_ADC_UpdateVoltage(void);
 
 float V8M_YY_Voltage_GetVolt(V8M_YY_ADC_ChannelType);
 
-void v8m_yy_adc_test(void);
-
 
 #endif

+ 0 - 4
controller_yy_app/v8/v8m_yy/bsp_V8M_YY_led.h

@@ -17,7 +17,3 @@ void v8m_yy_led_off(uint8_t color);
 void v8m_yy_led_on(uint8_t color);
 
 void v8m_yy_led_toggle(uint8_t color);
-
-#ifdef LED_TEST
-void v8m_yy_led_test(void);
-#endif

+ 0 - 1
controller_yy_app/v8/v8m_yy/bsp_V8M_YY_pwm.h

@@ -19,7 +19,6 @@ void Bsp_V8M_YY_PwmSetCHValue(uint8_t chNum , uint32_t value);
 
 uint32_t Bsp_V8M_YY_PwmGetCHValue(uint8_t m_ch);
 
-void v8m_yy_motor_pwm_test(void);
 
 void PWM_IS_ENABLE(void);
 

+ 26 - 48
controller_yy_app_controller_yy_board_flash_sdram_xip_debug/segger_embedded_studio/controlware_yy_app.emSession

@@ -24,13 +24,19 @@
   <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application"/>
   <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;controlware"/>
   <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;hardware"/>
+  <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;middleware"/>
+  <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;middleware;fatfs"/>
+  <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;middleware;fatfs;src"/>
+  <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;middleware;fatfs;src;portable"/>
+  <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;middleware;fatfs;src;portable;sdxc"/>
+  <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;middleware;hpm_sdmmc"/>
+  <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;middleware;hpm_sdmmc;lib"/>
+  <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;payload"/>
   <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;remote_controller"/>
   <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;software"/>
   <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;user_src"/>
-  <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;v8"/>
-  <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;application;v8;v8m"/>
   <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;boards"/>
-  <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;boards;controller_yy_board"/>
+  <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;drivers"/>
   <ProjectSessionItem path="controlware_yy_app;controlware_yy_app - controller_yy_board;utils"/>
  </Project>
  <Register1>
@@ -53,11 +59,11 @@
  </TraceWindow>
  <Watch1>
   <Watches active="1" update="Never">
-   <Watchpoint expression="u3_rx_fifo_buff" name="u3_rx_fifo_buff" radix="-1" linenumber="370" filename="../../controller_yy_app/software/drv_usart.c"/>
-   <Watchpoint expression="tx_buffer" name="tx_buffer" radix="-1" linenumber="707" filename="../../controller_yy_app/software/drv_usart.c"/>
-   <Watchpoint expression="u3_dma_tx_buff" name="u3_dma_tx_buff" radix="-1" linenumber="372" filename="../../controller_yy_app/software/drv_usart.c"/>
-   <Watchpoint expression="_u3_config" name="_u3_config" radix="-1" linenumber="374" filename="../../controller_yy_app/software/drv_usart.c"/>
-   <Watchpoint expression="u3_tx_fifo_buff" name="u3_tx_fifo_buff" radix="-1" linenumber="371" filename="../../controller_yy_app/software/drv_usart.c"/>
+   <Watchpoint expression="data_buf" name="data_buf" radix="-1" linenumber="184" filename="../../controller_yy_app/v8/v8m/bsp_V8M_flash.c"/>
+   <Watchpoint expression="status" name="status" radix="-1" linenumber="163" filename="../../controller_yy_app/v8/v8m/bsp_V8M_flash.c"/>
+   <Watchpoint expression="s_xpi_nor_config" name="s_xpi_nor_config" radix="-1" linenumber="32" filename="../../controller_yy_app/v8/v8m/bsp_V8M_flash.c"/>
+   <Watchpoint expression="read_value" name="read_value" radix="-1" linenumber="238" filename="../../controller_yy_app/v8/v8m/bsp_V8M_flash.c"/>
+   <Watchpoint expression="s_can_rx_buf" name="s_can_rx_buf" radix="-1" linenumber="90" filename="../../controller_yy_app/hardware/hard_can.c"/>
   </Watches>
  </Watch1>
  <Watch2>
@@ -70,46 +76,18 @@
   <Watches active="0" update="Never"/>
  </Watch4>
  <Files>
-  <SessionOpenFile windowGroup="DockEditLeft" x="33" y="369" useTextEdit="1" folds0="12,31,68,92,172,233,255,261,498,512" path="../../controller_yy_app/software/drv_usart.c" left="0" selected="1" top="208" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="36" y="15" useTextEdit="1" path="../../controller_yy_app/software/soft_inc/my_board.h" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="26" y="47" useTextEdit="1" path="../../controller_yy_app/hardware/hard_imu_uart3.c" left="0" top="33" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="8" y="20" useTextEdit="1" path="../../controller_yy_app/user_src/inc/test.h" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="19" y="237" useTextEdit="1" path="../../controller_yy_app/user_src/main.c" left="0" top="210" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="13" y="36" useTextEdit="1" path="../../controller_yy_app/hardware/hard_hdma_int.c" left="0" top="19" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="19" y="45" useTextEdit="1" path="../../controller_yy_app/software/soft_inc/drv_usart.h" left="0" top="28" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="4" y="91" useTextEdit="1" path="../../controller_yy_app/software/rkfifo.c" left="0" top="78" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/software/debug_printf.c" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="27" y="8" useTextEdit="1" path="../../controller_yy_app/hardware/hard_inc/hard_hdma_int.h" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="8" y="100" useTextEdit="1" path="D:/sdk_env/sdk_env-v1.8.0/hpm_sdk/soc/HPM6700/HPM6750/hpm_soc_irq.h" left="0" top="86" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="70" useTextEdit="1" path="D:/sdk_env/sdk_env-v1.8.0/hpm_sdk/drivers/inc/hpm_csr_drv.h" left="0" top="69" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="119" useTextEdit="1" path="D:/sdk_env/sdk_env-v1.8.0/hpm_sdk/soc/HPM6700/HPM6750/toolchains/reset.c" left="0" top="103" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="245" useTextEdit="1" path="D:/sdk_env/sdk_env-v1.8.0/hpm_sdk/drivers/src/hpm_uart_drv.c" left="0" top="229" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="21" y="46" useTextEdit="1" path="../../controller_yy_app/software/soft_gs.c" left="0" top="42" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="23" y="35" useTextEdit="1" path="../../controller_yy_app/software/soft_inc/soft_gs.h" left="0" top="19" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="12" y="17" useTextEdit="1" path="../../controller_yy_app/software/soft_port_uart4.c" left="0" top="2" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="18" y="165" useTextEdit="1" folds0="94" path="../../controller_yy_app/software/soft_sdcard.c" left="0" top="139" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="19" y="5" useTextEdit="1" path="../../controller_yy_app/hardware/hard_inc/hard_sdio_sd.h" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="38" y="25" useTextEdit="1" path="../../controller_yy_app/middleware/fatfs/src/portable/diskio.h" left="0" top="15" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="3603" useTextEdit="1" path="../../controller_yy_app/middleware/fatfs/src/common/ff.c" left="0" top="3588" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="13" y="94" useTextEdit="1" path="../../controller_yy_app/middleware/fatfs/src/common/ff.h" left="0" top="82" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="8" y="115" useTextEdit="1" path="../../controller_yy_app/middleware/fatfs/src/portable/diskio.c" left="0" top="115" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/middleware/fatfs/src/portable/sdxc/hpm_sdmmc_disk.c" left="0" top="249" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="19" y="20" useTextEdit="1" path="../../controller_yy_app/software/soft_inc/soft_sdcard.h" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="8" y="199" useTextEdit="1" path="../../controller_yy_app/middleware/fatfs/src/common/ffconf.h" left="0" top="187" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="24" y="6" useTextEdit="1" path="../../controller_yy_app/software/soft_time.c" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/hardware/hard_inc/hard_system.h" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/hardware/hard_inc/hard_system_delay.h" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/software/soft_can.c" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/software/soft_can_yy.c" left="0" top="21" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="55" y="258" useTextEdit="1" folds0="135" path="../../controller_yy_app/controlware/data_save.c" left="0" top="258" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/hardware/hard_flash_at45db.c" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/hardware/hard_flash_gd25q16.c" left="0" top="417" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/v8/v8m/bsp_V8M_flash.c" left="0" top="141" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/v8/v8m/bsp_V8M_adc.c" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/v8/v8m/bsp_V8M_GPIO_photo.c" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/v8/v8m/bsp_V8M_led.c" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/v8/v8m/bsp_V8M_pwm.c" left="0" top="0" codecName="Default"/>
-  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/hardware/hard_can.c" left="0" top="199" codecName="Default"/>
+  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="93" useTextEdit="1" path="../../controller_yy_app/user_src/main.c" left="0" top="77" codecName="Default"/>
+  <SessionOpenFile windowGroup="DockEditLeft" x="14" y="9" useTextEdit="1" path="../../controller_yy_app/hardware/hard_sdio_sd.c" left="0" top="0" codecName="Default"/>
+  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="727" useTextEdit="1" path="../../controller_yy_app/software/soft_sdcard.c" left="0" top="717" codecName="Default"/>
+  <SessionOpenFile windowGroup="DockEditLeft" x="14" y="6" useTextEdit="1" path="../../controller_yy_board/board.c" left="0" top="0" codecName="Default"/>
+  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_board/board.h" left="0" top="510" codecName="Default"/>
+  <SessionOpenFile windowGroup="DockEditLeft" x="0" y="0" useTextEdit="1" path="../../controller_yy_app/middleware/fatfs/src/portable/diskio.c" left="0" top="243" codecName="Default"/>
+  <SessionOpenFile windowGroup="DockEditLeft" x="69" y="141" useTextEdit="1" path="../../controller_yy_app/middleware/fatfs/src/portable/sdxc/hpm_sdmmc_disk.c" left="0" top="126" codecName="Default"/>
+  <SessionOpenFile windowGroup="DockEditLeft" x="18" y="638" useTextEdit="1" path="../../controller_yy_app/middleware/hpm_sdmmc/lib/hpm_sdmmc_host.c" left="0" top="630" codecName="Default"/>
+  <SessionOpenFile windowGroup="DockEditLeft" x="23" y="50" useTextEdit="1" path="D:/sdk_env/sdk_env-v1.8.0/hpm_sdk/soc/HPM6700/HPM6750/hpm_misc.h" left="0" top="36" codecName="Default"/>
+  <SessionOpenFile windowGroup="DockEditLeft" x="27" y="144" useTextEdit="1" path="../../controller_yy_app/hardware/hard_imu_uart3.c" left="0" top="130" codecName="Default"/>
+  <SessionOpenFile windowGroup="DockEditLeft" x="5" y="103" useTextEdit="1" path="../../controller_yy_app/hardware/hard_can.c" left="0" top="65" codecName="Default"/>
+  <SessionOpenFile windowGroup="DockEditLeft" x="16" y="9" useTextEdit="1" path="../../controller_yy_app/software/soft_can.c" left="0" selected="1" top="152" codecName="Default"/>
  </Files>
  <EMStudioWindow activeProject="controlware_yy_app - controller_yy_board" fileDialogDefaultFilter="*.c" autoConnectTarget="GDB Server" buildConfiguration="Debug" sessionSettings="" debugSearchFileMap="" fileDialogInitialDirectory="" debugSearchPath="" autoConnectCapabilities="1343"/>
 </session>

+ 5 - 1
踩坑.md

@@ -1 +1,5 @@
-1、需要DMA搬运的数据一定要加前缀 ATTR_PLACE_AT_NONCACHEABLE
+1、需要DMA搬运的数据一定要加前缀 ATTR_PLACE_AT_NONCACHEABLE
+
+2、没有内部可操作rom,外部的qspi-flash进行映射,操作时要减基地址0x80000000;
+
+看了一些博客,能够不按原来的要求初始地址处填充flash-cfg和boot头等文件,升级功能可参考1.10版本及以上sdk的ota与rom-ota。后续sdk包要进行升级适配。