/****************************************************************************** * @file bsp_zc.c * @brief PA1 过零:MCPWM FPIN 双沿中断,沿到则回调切继电器 * @author cyWu <1917507415@qq.com> * @date 2026.09.04 * @version V3.1.0 * @history * - V3.1.0, 2026.09.04, cyWu, 状态收进 BspZcCtx_t,去掉无用计数与排障史注释 * - V3.0.0, 2026.09.04, cyWu, MCPWM FPIN 硬件边沿中断 ******************************************************************************/ #include "system/includes.h" #include "asm/gpio.h" #include "asm/mcpwm.h" #include "asm/hwi.h" #include "asm/irq.h" #include "asm/timer.h" #include "bsp_zc.h" #include "board_pin.h" #include #define LOG_TAG_CONST APP #define LOG_TAG "[BSP_ZC]" #define LOG_INFO_ENABLE #include "debug.h" extern PWM_CH_REG *get_pwm_ch_reg(pwm_ch_num_type index); typedef struct { BspZcEdgeCb_t edge_cb; volatile uint32_t edge_cnt; volatile uint32_t last_edge_ms; volatile uint8_t last_level; uint8_t initialized; } BspZcCtx_t; static BspZcCtx_t s_zc; /** * @brief FPIN 边沿 ISR:清 pending、记沿、执行切变回调 * @note 中断上下文:禁止 printf / 写 VM / 切 BLE * @return 无 */ ___interrupt static void bsp_zc_interrupt(void) { if (JL_MCPWM->CH0_CON1 & BIT(15)) { JL_MCPWM->CH0_CON1 |= BIT(14); } else if (JL_MCPWM->CH1_CON1 & BIT(15)) { JL_MCPWM->CH1_CON1 |= BIT(14); } else if (JL_MCPWM->CH2_CON1 & BIT(15)) { JL_MCPWM->CH2_CON1 |= BIT(14); } else if (JL_MCPWM->CH3_CON1 & BIT(15)) { JL_MCPWM->CH3_CON1 |= BIT(14); } else { return; } s_zc.edge_cnt++; s_zc.last_edge_ms = (uint32_t)timer_get_ms(); s_zc.last_level = (uint8_t)gpio_read(BOARD_ZC_PIN); if (s_zc.edge_cb) { s_zc.edge_cb(); } } /** * @brief 把 PA1 接到一个 FPIN 通道(上升沿或下降沿) * @param index FPIN 通道 0~3 * @param rising 1=上升沿,0=下降沿 * @return 无 */ static void bsp_zc_fpin_channel_init(u8 index, u8 rising) { PWM_CH_REG *pwm_reg; if (index > 3) { return; } if (rising) { JL_MCPWM->FPIN_CON |= BIT(16 + index); } else { JL_MCPWM->FPIN_CON &= ~BIT(16 + index); } #if BOARD_ZC_FPIN_FILTER_EN JL_MCPWM->FPIN_CON |= BIT(8 + index); JL_MCPWM->FPIN_CON |= ((u32)BOARD_ZC_FPIN_FILTER & 0x3FUL); #else JL_MCPWM->FPIN_CON &= ~BIT(8 + index); #endif gpio_ich_sel_iutput_signal(BOARD_ZC_PIN, (enum INPUT_CH_SIGNAL)(INPUT_CH_SIGNAL_MC_FPIN0 + index), INPUT_CH_TYPE_GP_ICH); request_irq(IRQ_MCPWM_CHX_IDX, 3, bsp_zc_interrupt, 0); pwm_reg = get_pwm_ch_reg((pwm_ch_num_type)index); pwm_reg->ch_con1 = BIT(14) | BIT(11) | BIT(4) | (index << 0); JL_MCPWM->MCPWM_CON0 |= BIT(index); } /** * @brief 初始化 PA1 输入并挂双沿 FPIN 中断 * @param cb 沿回调,NULL 则只计数 * @return 无 */ void bsp_zc_init(BspZcEdgeCb_t cb) { if (s_zc.initialized) { return; } memset(&s_zc, 0, sizeof(s_zc)); s_zc.edge_cb = cb; gpio_set_die(BOARD_ZC_PIN, 1); gpio_set_direction(BOARD_ZC_PIN, 1); gpio_set_pull_up(BOARD_ZC_PIN, BOARD_ZC_PULL_UP); gpio_set_pull_down(BOARD_ZC_PIN, BOARD_ZC_PULL_DOWN); s_zc.last_level = (uint8_t)gpio_read(BOARD_ZC_PIN); #if BOARD_ZC_USE_IRQ bsp_zc_fpin_channel_init((u8)BOARD_ZC_FPIN_FALL_CH, 0); #if BOARD_ZC_FPIN_BOTH_EDGE bsp_zc_fpin_channel_init((u8)BOARD_ZC_FPIN_RISE_CH, 1); #endif #endif s_zc.initialized = 1; log_info("zc init irq=%d fall=%d rise=%d filt=%d lvl=%d\n", BOARD_ZC_USE_IRQ, BOARD_ZC_FPIN_FALL_CH, #if BOARD_ZC_FPIN_BOTH_EDGE BOARD_ZC_FPIN_RISE_CH, #else -1, #endif BOARD_ZC_FPIN_FILTER_EN, (int)s_zc.last_level); } /** * @brief 1ms 软件采样兜底(须由真实 1ms 定时器调用) * @return 无 */ void bsp_zc_scan_1ms(void) { uint8_t lvl; if (!s_zc.initialized) { return; } lvl = (uint8_t)gpio_read(BOARD_ZC_PIN); if (lvl != s_zc.last_level) { s_zc.last_level = lvl; s_zc.edge_cnt++; s_zc.last_edge_ms = (uint32_t)timer_get_ms(); if (s_zc.edge_cb) { s_zc.edge_cb(); } } } /** * @brief 累计过零沿次数 * @return 沿计数 */ uint32_t bsp_zc_edge_count(void) { return s_zc.edge_cnt; } /** * @brief 最近一次沿的时间戳 * @return timer_get_ms(),0=从未检测到 */ uint32_t bsp_zc_last_edge_ms(void) { return s_zc.last_edge_ms; } /** * @brief 当前 PA1 电平 * @return 0 或 1 */ uint8_t bsp_zc_level(void) { return (uint8_t)gpio_read(BOARD_ZC_PIN); }