This repository has been archived on 2025-02-28. You can view files and clone it, but cannot push or open issues or pull requests.
controller-hd/User/app.c

541 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @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();
}
}