Files
vd_960/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/peripheral_main.c
T
wangfq 0c717e4818 test(vd960DBN): 实验A — 跳过 offlog_boot SPI 写, 验证跑飞触发点 (2026-08-17)
日志诊断: RSTSCKR 全 0(非硬件复位) + snap ok 后 71B 乱码 + 无 ASCII 打印
→ PC 跑飞跳回 0x00000000 重启, 触发点锁定 offlog_boot(SPI 32B 页写)。
与 08-12 实验 99ef634 结论一致。

- offlog_boot() 调用 #if 0, 保留 RMVF 清除
- 新增 .noinit g_boot_count 计数器: 每次 main 重进 +1 并打印 BOOT_CNT
  (跑飞重启不清零, 区分真复位 vs 跑飞)
- 新增 EXPA: offlog_boot skipped 标记打印

预期: 不崩 → offlog_boot 写实锤; 仍崩 → 跑飞点下移 load_cfg/output_cfg
2026-08-17 10:04:52 +08:00

449 lines
14 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.
/********************************** (C) COPYRIGHT *******************************
* File Name : main.c
* Author : WCH
* Version : V1.1
* Date : 2020/08/06
* Description : Peripheral slave application main function and task system initialization
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/
/******************************************************************************/
/* Header file contains */
#include "CONFIG.h"
#include "HAL.h"
#include "gattprofile.h"
#include "peripheral.h"
#include "cmcng.h"
#include <string.h>
#include "dbn_ble_srv.h"
#include "eth_driver.h"
#include "net_srv.h"
#include "storage.h"
#include "offlog.h"
#include "snapshot.h"
#include "tcp_json_srv.h"
#include "loop_uart_proto.h"
#include "iot_mqtt_srv.h"
#include "fault_diag.h"
/*********************************************************************
* GLOBAL TYPEDEFS
*/
__attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4];
#define KEY_GPIO (RCC_APB2Periph_GPIOA)
#define KEY_BV BV(0)
#define KEY_IN (GPIO_ReadInputDataBit(KEY_GPIO, KEY_BV)==0)
#define HAL_PUSH_BUTTON() (KEY1_IN) //Add custom button
#if(defined(BLE_MAC)) && (BLE_MAC == TRUE)
const uint8_t MacAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
// #else
// uint8_t MACAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
#endif
uint8_t gMacAddr[6] = { 0x38, 0x3B, 0x26, 0x11, 0xA4 ,0x35 };
/* Used for app judgment file effectiveness */
const uint32_t Address = 0xFFFFFFFF;
__attribute__((aligned(4))) uint32_t Image_Flag __attribute__((section(".ImageFlag"))) = (uint32_t)&Address;
uint8_t g_dev_number[6] = ""; // Ʒ
uint8_t g_dev_password[6] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36};
uint8_t g_ble_safe_flag = 0;
uint32_t g_ble_safe_counter_ori = 0;
uint32_t g_ble_safe_counter_dst = 0;
char g_flag_debug = 1;
uint8_t g_dg_device_type = DDType_DLD950V4; // ????????????????
uint8_t g_dg_sub_dev_type = DDType_DLD950V4;
Sub_Code_Enable g_sub_code_enable = {0,};
uint32_t g_activ_counter = 0;
uint32_t g_counter_bt_timeout = 0;
uint8_t g_flag_bt_state = 0;
uint8_t g_flag_bt_disable = 0;
uint8_t g_max_counter_bt_min = 0;
uint32_t g_max_counter_bt_timeout = 0; //BT_DISABLE_IDLE_TIMEOUT * 60 * 1000; // ms unit
__IO uint32_t TimingDelayInc;
__IO uint32_t TimingDelayDec;
uint8_t trigB;
Pkg_Uart g_pkg_uart_1 = { 0, 0, 0, "", 0};
Pkg_Uart g_pkg_uart_2 = { 0, 0, 0, "", 0};
Flag_Counter g_flag_counter_key = {0, 0, 0};
Flag_Counter g_flag_counter_ota = {0, 0, 0};
uint8_t g_storage_uart_num = 0;
uint32_t g_storage_uart_baud = 19200;//9600;
uint8_t g_storage_uart_num_2 = 1;
uint32_t g_storage_uart_baud_2 = 115200; //115200;
/* 实验A诊断 (2026-08-17): .noinit boot 计数器 — 跑飞重启不清零, 每次 main 重进 +1.
真复位(POR/IWDG/软复位)后 .bss 清零但 .noinit 保留, 可区分复位与跑飞重启 */
uint32_t g_boot_count __attribute__((section(".noinit")));
uint32_t mstick(void){
return TimingDelayInc;
}
void InitPkgUart(Pkg_Uart * pkg){
memset(pkg->pkg, 0, BUFF_STACK_SIZE);
pkg->flag = 0;
pkg->tick = 0;
pkg->len = 0;
pkg->offset = 0;
}
/*********************************************************************
* @fn TIM2_Init
*
* @brief Initializes TIM2.
*
* @return none
*/
void TIM2_Init( void )
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure={0};
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / 1000000;
TIM_TimeBaseStructure.TIM_Prescaler = WCHNETTIMERPERIOD * 1000 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM2, TIM_IT_Update ,ENABLE);
TIM_Cmd(TIM2, ENABLE);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update );
NVIC_EnableIRQ(TIM2_IRQn);
}
/*********************************************************************
* @fn TIM3_Init
*
* @brief Initializes TIM3.
*
* @return none
*/
void TIM3_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure={0};
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = { 0 };
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
////10ms
// TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / 1000000;
// TIM_TimeBaseStructure.TIM_Prescaler = 10 * 1000 - 1;
//1ms
TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / 1000000;
TIM_TimeBaseStructure.TIM_Prescaler = 1 * 1000 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM3, ENABLE);
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
NVIC_EnableIRQ(TIM3_IRQn);
}
void key_event_srv(void){
// if(g_flag_counter_key.tick > 1000){
// PRINT("key_tick_timeup_______: %d\n", GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0));
// g_flag_counter_key.tick = 0;
// }
if(g_flag_counter_key.flag){
uint8_t _pkg[7] = {0};
uint8_t i = 0;
switch (g_flag_counter_key.flag) {
case KEY_ET_BLE_ENABLE: {
PRINT("______KEY_ET_BLE_ENABLE\n");
NVIC_SystemReset();
} break;
case KEY_ET_REBOOT: {
PRINT("__________KEY_ET_REBOOT\n");
_pkg[i++] = 0x7F;
_pkg[i++] = 0x00;
_pkg[i++] = 0x01;
_pkg[i++] = 0x6D;
_pkg[i++] = 0x6C;
_pkg[i++] = 0x6E;
UART2_SendString(_pkg, i); //1 send loop mcu reboot;
Delay_Ms(10);
// 2 DBN dev reboot
NVIC_SystemReset();
} break;
case KEY_ET_FACTORY: {
PRINT("_____________KEY_ET_FACTORY\n");
_pkg[i++] = 0x7F;
_pkg[i++] = 0x00;
_pkg[i++] = 0x01;
_pkg[i++] = 0x92;
_pkg[i++] = 0x93;
_pkg[i++] = 0x93;
UART2_SendString(_pkg, i); //1 send loop mcu factory init
} break;
case KEY_ET_NETBLE_FACTORY: {
//2 DBN dev factory init;
factory_dev_info();
Delay_Ms(10);
NVIC_SystemReset();
} break;
}
g_flag_counter_key.flag = 0;
}
}
/*********************************************************************
* @fn Main_Circulation
*
* @brief Main loop
*
* @return none
*/
__attribute__((section(".highcode")))
__attribute__((noinline))
void Main_Circulation(void)
{
uint32_t _counter = 0;
while(1)
{
FAULT_MARKER(MK_LOOP_TOP);
iot_watchdog_kick(); /* 无条件喂狗 (2026-08-13): 原只在 iot_mqtt_poll, tcp_json 分支不喂 */
TMOS_SystemProcess();
if(g_net_state.flag < 2)
{
net_srv_init();
}
if(g_net_state.flag == 2)
{
if(g_sub_code_enable.iot_enable){
if(iot_net_info.mode == IOT_Addr_IP_Mode){
if(get_ipstr_to_array(iot_net_info.remote_addr, RemoteIP) == 0){
WCHNET_CreateTcpMqttSocket();
}
}
else{
//DNS
}
}
else
{
WCHNET_CreateTcpSocket();
}
}
/*Ethernet library main task function,
* which needs to be called cyclically*/
WCHNET_MainTask();
/*Query the Ethernet global interrupt,
* if there is an interrupt, call the global interrupt handler*/
if(WCHNET_QueryGlobalInt())
{
WCHNET_HandleGlobalInt();
}
FAULT_MARKER(MK_UART_SRV_IN);
uart_srv();
FAULT_MARKER(MK_UART_SRV_OUT);
snap_flush(); /* 快照落盘: 无条件挂主循环 (原在 iot_enable 分支, TCP 模式不落盘) */
FAULT_MARKER(MK_POLL_BLE_IN);
poll_dbn_ble();
if (g_sub_code_enable.iot_enable) {
iot_mqtt_publish_sensor(); // Push 0xC0 sensor data to MQTT broker
iot_mqtt_poll(); // IoT MQTT state machine + PINGREQ keepalive
} else {
tcp_json_push_sensor(); // Push 0xC0 sensor data to TCP JSON client
tcp_json_poll();
}
key_event_srv();
}
}
/*********************************************************************
* @fn main
*
* @brief Main function
*
* @return none
*/
int main(void)
{
SystemCoreClockUpdate();
Delay_Init();
#ifdef DEBUG
// USART_Printf_Init( 115200 );
USART_Printf_Init( 256000 );
#endif
/* 诊断: 复位原因寄存器 (bit31=IWDG bit30=WWDG bit29=LPWR bit26=NRST bit25=POR bit24=软复位)
每次上电必打, 区分看门狗死锁 vs 掉电 vs 外部复位 */
PRINT("RST_REASON: 0x%08lx\n", (unsigned long)OFFLOG_RCC_RSTSCKR);
g_boot_count++;
PRINT("BOOT_CNT: %lu\n", (unsigned long)g_boot_count);
fault_diag_init(); /* 打印上次复位现场 (HardFault mcause/mepc + 执行轨迹 marker) */
iot_watchdog_init(); /* 无条件 IWDG (2026-08-13): iot_enable=0 时 iot_mqtt_init 不调,
卡死无兜底 → 永久冻结。IWDG 4s 超时 + 主循环喂狗 */
PRINT("%s\n", VER_LIB);
PRINT("SystemCoreClock:%d\n", SystemCoreClock);
/* ===== 实验: 禁用全部 Flash/SPI 操作 (2026-08-12) =====
结论: 禁用后设备稳定 → SPI 操作触发复位+乱码实锤
软件缓解: storage.c SPI 时钟降档 + GPIO 缓边沿 (见 SPI_Flash_Init)
硬件根治: NRST 加 100nF 电容 / SPI 走线远离 NRST / 串阻缓边沿
#if 0 = 恢复全部 SPI; 保留本块便于回退实验 */
#if 0
PRINT("ISOLATE: flash/SPI disabled (flash isolation test)\n");
#else
GetMacAddr(gMacAddr);
storage_init();
PRINT("INIT: storage ok\n");
offlog_init();
PRINT("INIT: offlog ok\n");
/* 快照区: 上电扫描恢复 (2026-08-14, printf 重入修复后恢复启用) */
snap_init();
PRINT("INIT: snap ok\n");
/* ===== 实验A (2026-08-17): 跳过 offlog_boot SPI 写 — 验证跑飞触发点 =====
背景: 日志 RSTSCKR 全 0(非硬件复位) + snap ok 后 71B 乱码 + 无 ASCII
→ PC 跑飞跳回 0x00000000 重启, 触发点在 offlog_boot(SPI 32B 页写)
与 08-12 实验 99ef634 一致: 跳过 offlog_boot 写 → 不崩
不崩 → offlog_boot 写实锤; 仍崩 → 跑飞点下移 load_cfg/output_cfg
验证后恢复: 取消 #if 0, 并视结果考虑延后到主循环喂狗后执行 */
{
uint32_t rcc_rst = OFFLOG_RCC_RSTSCKR;
#if 0
offlog_boot(rcc_rst);
#else
PRINT("EXPA: offlog_boot skipped\n");
#endif
OFFLOG_RCC_RSTSCKR |= OFFLOG_RST_RMVF; /* RMVF (bit24): 清复位标志 */
}
load_cfg_from_flash();
output_cfg_from_flash();
#endif
PRINT("MAC: %02X %02X %02X %02X %02X %02X\r\n", gMacAddr[0],gMacAddr[1], gMacAddr[2], gMacAddr[3],gMacAddr[4],gMacAddr[5]);
PRINT("net version:%x\n", WCHNET_GetVer());
WCHBLE_Init();
HAL_Init();
uart_init();
/* ===== 实验: 禁用 UART2 (Loop 口) 隔离测试 (2026-08-12) =====
结论: UART2 禁用后仍复位 → 与 Loop 数据路径无关 (后定位为 SPI 串扰)
#if 0 = 恢复 UART2 正常 */
#if 0
{
GPIO_InitTypeDef gpio;
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
USART_Cmd(USART2, DISABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
gpio.GPIO_Pin = GPIO_Pin_3;
gpio.GPIO_Mode = GPIO_Mode_IPU; /* PA3 脱离 UART2, 上拉输入 */
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio);
PRINT("ISOLATE: UART2 disabled (Loop isolation test)\n");
}
#endif
TIM3_Init();
TIM2_Init();
GAPRole_PeripheralInit();
Peripheral_Init();
Main_Circulation();
}
void TIM3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
/*********************************************************************
* @fn TIM3_IRQHandler, 1ms
*
* @brief This function handles TIM2 exception.
*
* @return none
*/
void TIM3_IRQHandler(void)
{
TimingDelayInc++;
g_activ_counter++;
if(g_pkg_uart_2.offset){
if(g_pkg_uart_2.flag == 0){
g_pkg_uart_2.tick++;
if(g_pkg_uart_2.tick > 8){
g_pkg_uart_2.flag = 1;
}
}
}
// Safety: reset frame parser if stuck in non-IDLE state too long
if(g_lup_parser.state != LUP_FRAME_STATE_IDLE){
if(g_pkg_uart_2.tick > 20){
lup_frame_reset();
g_pkg_uart_2.tick = 0;
}
}
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0){//HAL_PUSH_BUTTON()){
g_flag_counter_key.tick++;
}
else{
if(g_flag_counter_key.tick){
if(g_flag_counter_key.tick < 2000){
g_flag_counter_key.flag = KEY_ET_BLE_ENABLE;
}
else if(g_flag_counter_key.tick < 6000){
g_flag_counter_key.flag = KEY_ET_REBOOT;
}
else if(g_flag_counter_key.tick < 10000){
g_flag_counter_key.flag = KEY_ET_FACTORY;
}
else{
g_flag_counter_key.flag = KEY_ET_NETBLE_FACTORY;
}
g_flag_counter_key.tick = 0;
}
}
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
/******************************** endfile @ main ******************************/