Files
vd_960/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/peripheral_main.c
T
wangfq 452ff68bae test(vd960DBN): 实验D — 栈空间诊断 + load_cfg/output_cfg 触发点验证 (2026-08-17)
新证据: BOOT_CNT@0x2000f854 = .noinit 被推到 RAM 顶, 栈顶(0x20010000)
之下仅 ~1.9KB → .bss≈46KB (BLE/WCHNET/SPI_FLASH_BUF 等大数组挤占)。
栈溢出 → 覆盖 .noinit(g_boot_count 恒1/g_fault_diag 消失) + 覆盖返回地址
→ PC 跑飞跳回 0 → 循环。快照延后无效因为问题不是快照 SPI 而是栈空间。

- BOOT_CNT 打印加 _end(堆起点, 反推.bss大小) + 当前 SP(栈深)
- load_cfg/output_cfg #if 0 (EXPD 标记): 稳定→触发点确认; 仍崩→更晚
- 待用户提供编译后 .map 确认 .bss 组成
2026-08-17 11:00:03 +08:00

461 lines
15 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 分支不喂 */
snap_delayed_init(); /* 快照区延后初始化: 开机 3s 后首次进入执行 (2026-08-17) */
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++;
{
extern char _end[]; /* 堆起点 = .bss 末尾 (Link.ld) */
uint32_t _sp;
__asm__ volatile("mv %0, sp" : "=r"(_sp));
PRINT("BOOT_CNT:%lu @0x%08lx END:0x%08lx SP:0x%08lx\n",
(unsigned long)g_boot_count, (unsigned long)&g_boot_count,
(unsigned long)_end, (unsigned long)_sp);
/* 判读(2026-08-17): BOOT_CNT@0x2000f854 → .noinit 被推到 RAM 顶,
栈顶 0x20010000 之下仅 ~1.9KB → .bss≈46KB(大数组), 栈溢出风险!
END = 堆起点(.bss 末): END - 0x20004000 - .data ≈ .bss 大小;
SP = 当前栈深(main 入口浅栈处, 栈顶下方 ~几十字节) */
}
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-17) — snap_init 移到主循环 3s 后
(snap_delayed_init), 避开启动早期 SPI 重负载窗口 (擦+整扇区写回 ~80ms);
3s 内的传感帧由 snap_enqueue/snap_flush 的 !_ready 门控自动丢弃不落盘 */
/* offlog_boot: 记录本次复位原因到事件日志。
实验A(2026-08-17, 跳过offlog_boot仍崩)证明其非跑飞触发点 → 已恢复 */
{
uint32_t rcc_rst = OFFLOG_RCC_RSTSCKR;
offlog_boot(rcc_rst);
OFFLOG_RCC_RSTSCKR |= OFFLOG_RST_RMVF; /* RMVF (bit24): 清复位标志 */
}
/* ===== 实验D (2026-08-17): 验证 load_cfg/output_cfg 是否为栈溢出触发点 =====
BOOT_CNT@0x2000f854 → 栈≈1.9KB (极小)。此二函数含 malloc(512B)+
SPI_Flash_Read+大量 printf(%s), 栈峰值可能触顶。
稳定 → 触发点确认(此处栈深); 仍崩 → 触发点在别处(BLE init等) */
#if 0
load_cfg_from_flash();
output_cfg_from_flash();
#else
PRINT("EXPD: load_cfg/output_cfg skipped\n");
#endif
#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 ******************************/