541 lines
16 KiB
C
541 lines
16 KiB
C
/**
|
||
* @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
|
||
|
||
#if HART_SOFTWARE_TEST_ENABLE == TRUE
|
||
ENABLE_TIM(HART_TIM);
|
||
// 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();
|
||
}
|
||
}
|