/** * @file app.c * @author xxx * @date 2023-08-30 08:58:43 * @brief app初始化和app启动 * @copyright Copyright (c) 2023 by xxx, All Rights Reserved. */ #include "app.h" #include "adcs.h" #include "menus.h" #include "test_bsp.h" #include "bootload.h" #include "wl_flash.h" #include "fal_execution.h" noinit_data_t noinit_data __attribute__((section("NOINIT"), zero_init)); // 非初始化数据 https://blog.51cto.com/u_15427821/4586693 __IO udevice_t udevice __attribute__((section("NOINIT"), zero_init)); // 设备参数 __IO rt_save_param_t rt_save __attribute__((section("NOINIT"), zero_init)); // 实时参数 __IO calib_param_t calib_param[CALIBPARA_MAX] __attribute__((section("NOINIT"), zero_init)); // 校准参数 pressure_calib_param_t pressure_calib_param[PRESSURE_PARAM_MAX] __attribute__((section("NOINIT"), zero_init)); // 压力校准参数 __IO real_time_data_t rt_data; // 实时参数 pid_t _pid; // pid参数 driver_icon_enable_u driver_icon_enable; // 驱动使能图标 // 模拟量 __IO uint16_t adc_raw[ADC1_MAX]; // ADC原始值 __IO const static uint32_t cupid_encrypt = 0xFFFFFFFF; /** * @brief 重新加载非初始化数据 * * 如果非初始化数据的复位标志位为NOINIT_NORESET_FLAG,则重新加载相关参数并初始化工作模式和定时器。 * 如果复位标志位不是NOINIT_NORESET_FLAG,则将复位标志位设置为NOINIT_NORESET_FLAG。 */ static BOOL noinit_data_reload(void) { uint32_t crc = 0; if (noinit_data.rest_flag == NOINIT_NORESET_FLAG) { crc = crc32_compute((uint8_t *)&noinit_data, sizeof(noinit_data_t) - sizeof(uint32_t)); if (crc != noinit_data.crc) { osel_memset((uint8_t *)&noinit_data, 0, sizeof(noinit_data_t)); return FALSE; } crc = crc32_compute((uint8_t *)&udevice, sizeof(udevice_t) - sizeof(uint32_t)); if (crc != udevice.crc || udevice.dev_version != CURRENT_VERSION) { return FALSE; } // 如果是上电重启需要将数据复制到相关参数中 if (noinit_data.flag.bits.reset_or_power_on == TRUE) { osel_memset((uint8_t *)&calib_param, 0, (CALIBPARA_MAX * sizeof(calib_param_t))); osel_memset((uint8_t *)&udevice, 0, sizeof(udevice_t)); osel_memset((uint8_t *)&rt_data, 0, sizeof(real_time_data_t)); osel_memset((uint8_t *)&mode_params, 0, sizeof(mode_params_u)); udevice.display_language = noinit_data.language; udevice.inst_mode = noinit_data.inst_mode; udevice.control_mode = noinit_data.control_mode; udevice.dev_algorithm_mode = noinit_data.dev_algorithm_mode; if (udevice.control_mode == DIGITAL_CTRL_MODE) { rt_save.travel_set_pt = ((float32)(noinit_data.travel_set_pt)) * 0.1f; } if (noinit_data.dev_model != 0) { udevice.dev_model = noinit_data.dev_model; } else { return FALSE; } if (noinit_data.dead_zone != 0) { udevice.integral_db = noinit_data.dead_zone; } else { return FALSE; } if (noinit_data.loop.is_calibration == TRUE) { osel_memcpy((uint8_t *)&calib_param[CALIBPARA_LOOP], (uint8_t *)&noinit_data.loop, sizeof(calib_param_t)); } else { return FALSE; } if (noinit_data.loop_output.is_calibration == TRUE) { osel_memcpy((uint8_t *)&calib_param[CALIBPARA_VIP], (uint8_t *)&noinit_data.loop_output, sizeof(calib_param_t)); } if (noinit_data.pressure_s.is_calibration == TRUE) { osel_memcpy((uint8_t *)&calib_param[CALIBPARA_PS], (uint8_t *)&noinit_data.pressure_s, sizeof(calib_param_t)); } switch (udevice.dev_algorithm_mode) { case MODE_VARIABLE_FREQUENCY_CONTROL_ALGORITHM: osel_memcpy((uint8_t *)&mode_params.control, noinit_data.mode_params, sizeof(mode_control_storage_t)); break; case MODE_SPEED_CONTROL_ALGORITHM: osel_memcpy((uint8_t *)&mode_params.pwmp, noinit_data.mode_params, sizeof(pwmp_storage_pars_t)); break; default: return FALSE; } } mode_init(); // 工作模式初始化 mode_master_detection(); // 工作模式控制管理 ENABLE_TIM(MODE_GATHE_TIM); // Enable MODE_GATHE_TIM ENABLE_TIM(MODE_TIM); // MODE_TIM用于算法控制 return TRUE; } else { return FALSE; } } /** * @brief 设置未初始化的数据 * * 此函数用于设置未初始化的数据。 * * @note 这是一个静态函数,只能在当前文件内被调用。 */ void noinit_data_set(void) { noinit_data.language = udevice.display_language; noinit_data.inst_mode = udevice.inst_mode; noinit_data.control_mode = udevice.control_mode; noinit_data.dev_algorithm_mode = udevice.dev_algorithm_mode; if (noinit_data.control_mode == DIGITAL_CTRL_MODE) { noinit_data.travel_set_pt = (int16_t)(rt_save.travel_set_pt * 10); } else { noinit_data.travel_set_pt = 0; } if (udevice.dev_model != 0) { noinit_data.dev_model = udevice.dev_model; } if (udevice.integral_db != 0) { noinit_data.dead_zone = udevice.integral_db; } if (calib_param[CALIBPARA_LOOP].is_calibration == TRUE) { osel_memcpy((uint8_t *)&noinit_data.loop, (uint8_t *)&calib_param[CALIBPARA_LOOP], sizeof(calib_param_t)); } if (calib_param[CALIBPARA_VIP].is_calibration == TRUE) { osel_memcpy((uint8_t *)&noinit_data.loop_output, (uint8_t *)&calib_param[CALIBPARA_VIP], sizeof(calib_param_t)); } if (calib_param[CALIBPARA_PS].is_calibration == TRUE) { osel_memcpy((uint8_t *)&noinit_data.pressure_s, (uint8_t *)&calib_param[CALIBPARA_PS], sizeof(calib_param_t)); } // 如果模式正在调整,则不保存参数 if (mode_get()->interface_req.mode_is_adjusting() == FALSE) { switch (udevice.dev_algorithm_mode) { case MODE_VARIABLE_FREQUENCY_CONTROL_ALGORITHM: if (mode_params.control.tuned_flag == TUNED_SUCCESS) { osel_memcpy(noinit_data.mode_params, (uint8_t *)&mode_params.control, sizeof(mode_control_storage_t)); } break; case MODE_SPEED_CONTROL_ALGORITHM: if (mode_params.pwmp.tuned_flag == TUNED_SUCCESS) { osel_memcpy(noinit_data.mode_params, (uint8_t *)&mode_params.pwmp, sizeof(pwmp_storage_pars_t)); } break; default: break; } } } /** * @brief 从EEPROM中读取未初始化的数据 * * 该函数从EEPROM中读取未初始化的数据,并调用noinit_data_reload函数处理这些数据。 * * @return 如果成功读取并处理数据,则返回TRUE;否则返回FALSE。 */ static BOOL noinit_data_read_epprom(void) { // 从EPPROM中读取 if (fal_execution_kv_read(KEY_NOINIT_DATA, (uint8_t *)&noinit_data, sizeof(noinit_data_t)) == FALSE) { return FALSE; } return noinit_data_reload(); } /** * @brief 保存板载数据到Flash * * 该函数首先擦除存储板载数据的Flash区域,然后将板载数据写入到该区域。 * */ void board_data_save(void) { wl_flash_erase(&wl_flash_board_data); wl_flash_write(&wl_flash_board_data, (uint8_t *)&board_data, sizeof(board_data_t)); } #ifndef BOOTLOAD // 非bootload模式 static void bootload_preload(void) { set_app_preload_bootload_flag(BOOTLOAD_UNSET_FLAG); if (get_app_preload_bootload_jump_flag() == APP_PRELOAD_BOOTLOAD_JUMP_IMMEDIATELY) // 通过标志位判断是否跳转到BOOTLOAD { DBG_ASSERT(FALSE __DBG_LINE); set_app_preload_bootload_jump_flag(APP_PRELOAD_BOOTLOAD_JUMP_NONE); // 反初始化所有硬件 board_dinit(); LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_SYSCFG); LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_PWR); bootload_jump(BOOTLOAD_START_ADDRESS); } } static void app_preload_logo(BOOL is_first) { if (is_first) { menus_init(udevice.display_language); } else { menus_set_work_index(get_work_page_index()); menus_set_language(get_language()); } if (is_lcd_ext_board() == TRUE) { get_menus()->accelerate = TRUE; #if LCD_DESIGN == FALSE menus_loading_draw(is_first); #else menus_jump(MENUS_MAIN, TRUE); #endif gui_flush(); } } static void app_preload(void) { get_cpu_id((uint32_t *)rt_data.cpuid); #if CPU_ENCRYPT_ENABLE == TRUE if (cpu_judge_encrypt(board_data.app_preload_cupid_encrypt) == FALSE) { // 加密错误 while (1) { __NOP(); // 程序被拷贝才会运行到这里 } } #endif bootload_preload(); if (is_lcd_ext_board() == TRUE) { #if LCD_DESIGN == FALSE app_preload_logo(FALSE); #endif } } /** * @brief BOOTLOAD传输数据 * @param {uint8_t} *data * @param {uint16_t} len * @return {*} * @note */ static void bootload_transmit(const uint8_t data_src, const uint8_t *data, const uint16_t len) { extern uart_t *uarts[APP_UART_MAX]; uart_send_data(uarts[data_src], (uint8_t *)data, len); } /** * @brief BOOTLOAD更新完成处理 * @return {*} * @note BOOTLOAD更新完成恢复业务流程,这个时候不要重启 */ static void bootload_end(BOOL bootload_write_flag) { set_app_preload_bootload_flag(BOOTLOAD_UNSET_FLAG); // 更新完成恢复业务流程 if (bootload_write_flag == TRUE) { set_app_preload_bootload_jump_flag(APP_PRELOAD_BOOTLOAD_JUMP_WAIT); // 更新完成等待用户通知跳转到bootload } else { set_app_preload_bootload_jump_flag(APP_PRELOAD_BOOTLOAD_JUMP_NONE); // 更新失败 通知用户 } } #endif // 启动电压电量检查 static void startup_power_on_diagnosis(void) { BOOL is_low_battery = FALSE; float32 voltage = 0.0f; float32 current = 0.0f; static float32 voltage_last = 0.0f; static float32 current_last = 0.0f; BOOL voltage_right = FALSE; BOOL current_right = FALSE; for (;;) { LL_mDelay(200); voltage = get_cpu_volt(); current = get_current_by_resistance(); if (IS_BETWEEN(voltage, CPU_VREF_RUN_MIN, CPU_VREF_RUN_MAX) && current >= INPUT_CURRENT_RUN) { break; } // 这里需要在LCD上显示电量不足的LOG if (is_low_battery == FALSE || (voltage_last != voltage || current_last != current)) { voltage_right = IS_BETWEEN(voltage, CPU_VREF_RUN_MIN, CPU_VREF_RUN_MAX); current_right = current >= INPUT_CURRENT_RUN; voltage_last = voltage; current_last = current; menus_init(CHINESE); if (is_lcd_ext_board() == TRUE) { menus_low_battery_draw(voltage, voltage_right, current, current_right); gui_flush(); } is_low_battery = TRUE; } } } // 考虑到主频加速,除非PVD中断响应不一定成功 /** * @brief PVD掉电检测功能回调处理 * * 将系统切换到低功耗模式,关闭特定定时器、关闭特定电源、反初始化外设和驱动等。 * * @return 无返回值 */ // static void pvd_low(void) // { // // 设置掉电标志位 // { // power_on.flag = PVD_RESET_FLAG; // osel_memcpy(power_on.time.data, (uint8_t *)rt_save.real_time.data, ARRAY_LEN(rt_save.real_time.data)); // wl_flash_write(&wl_flash_power_on, (uint8_t *)&power_on, sizeof(device_reset_t)); // } // } /** * @brief app初始化 * @return {*} * @note */ void app_init(void) { #if DEBUG_ENABLE == TRUE #endif rt_data.flag.bits.app_init_over = FALSE; uint16_t size = 0; #ifndef BOOTLOAD // 非bootload模式 { LCD_POWER_ON(); // 打开LCD,3000的LED电源来自LCD供电 leds_on(LEDS_RED); startup_power_on_diagnosis(); // 启动电源检查,内部电压>=CPU_VREF,且输入电流>=INPUT_CURRENT_RUN leds_off_all(); wl_flash_init(&wl_flash_board_data); // 第一次上电如果noinit_data.rest_flag!=NOINIT_NORESET_FLAG 那么是断电重启 if (noinit_data.rest_flag != NOINIT_NORESET_FLAG) { noinit_data.flag.bits.reset_or_power_on = TRUE; } else { noinit_data.flag.bits.reset_or_power_on = FALSE; } // 如果是程序复位优先启动控制模块:<=200ms if (!noinit_data_reload()) { noinit_data.rest_flag = 0xFFFF; udevice.display_language = ENGLISH; } app_preload_logo(TRUE); system_clock_config_high(); // 切换高频 // fal初始化 { size = 0; size += sizeof(calib_param_t) * CALIBPARA_MAX; size += sizeof(mode_params_u); size += sizeof(specification_table_data_t); fal_execution_init(FAL_EXECUTION_EEPROM_M95_1, size); fal_execution_set_enable(FAL_EXECUTION_EEPROM_M95_1, TRUE); size = 0; fal_execution_init(FAL_EXECUTION_EEPROM_M95_2, size); fal_execution_set_enable(FAL_EXECUTION_EEPROM_M95_2, TRUE); size = 0; size += sizeof(udevice_t); size += sizeof(noinit_data_t); size += sizeof(diag_result_t); size += sizeof(rt_save_param_t); fal_execution_init(FAL_EXECUTION_EEPROM_FM24, size); fal_execution_set_enable(FAL_EXECUTION_EEPROM_FM24, TRUE); fal_execution_status_set(FAL_EXECUTION_EEPROM_M95_1, TRUE); fal_execution_status_set(FAL_EXECUTION_EEPROM_M95_2, TRUE); fal_execution_status_set(FAL_EXECUTION_EEPROM_FM24, TRUE); } system_clock_config_low(); leds_on(LEDS_GREEN); // 断电重启:优先启动控制模块 <=2000ms if (noinit_data.rest_flag == 0) { if (!noinit_data_read_epprom()) { noinit_data.rest_flag = 0xFFFF; } } key_init(); // 按键初始化 diagnosis_init(); // 诊断模块初始化 params_init(); // 参数初始化 if (noinit_data.rest_flag != NOINIT_NORESET_FLAG) { noinit_data.rest_flag = NOINIT_NORESET_FLAG; // 复位标志位 mode_init(); // 工作模式初始化 ENABLE_TIM(MODE_GATHE_TIM); // Enable MODE_GATHE_TIM ENABLE_TIM(MODE_TIM); // MODE_TIM用于算法控制 } app_preload(); // 预加载 app_hart_init(); // HART初始化,mode中的模拟诊断需要用到HART变量 flow_init(); // 流程初始化 power_on_diagnosis(); // 自检 bootload_init(bootload_transmit, bootload_end); // 在用户代码中接受更新文件需要初始化bootload } #else // bootload模式 // 在BOOTLOAD模式下需要关闭所有外设,且不需要接受用户代码,所以不需要初始化 board_dinit(); leds_off_all(); // 关闭所有LED #endif rt_data.flag.bits.app_init_over = TRUE; ENABLE_TIM(TASK_TIM); // Enable TASK_TIM ENABLE_TIM(HART_TIM); #if HART_SOFTWARE_TEST_ENABLE == TRUE // HART测试不允许有中断,否则串口异常会丢失导致测试失败 DISABLE_TIM(MODE_TIM); DISABLE_TIM(MODE_GATHE_TIM); fal_execution_inspection_sem(); #endif #if DEBUG_ENABLE == TRUE #endif } /** * @brief app反初始化 * @return {*} * @note */ void app_dinit(void) { hart_uart_dinit(); hart_ble_dinit(); } /** * @brief 业务流程启动 * @return {*} * @note */ void app_start(void) { // 板卡工作停止或运行 board_work_stop_or_run(); // BOOTLOAD标志位,执行业务流程 if (get_app_preload_bootload_flag() == BOOTLOAD_UNSET_FLAG) { flow_start(); } else { bootload_flow_start(); } }