Files
JBao_Door_Clamp_FW/apps/usr_periph/bsp_hw.c
T

430 lines
10 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 bsp_hw.c
* @brief CBC2 板级 GPIO / ADC:电机 H 桥、LED、按键、充电检测
* @author cyWu <1917507415@qq.com>
* @date 2026.08.24
* @version V1.4.0
* @history
* - V1.0.0, 2026.08.21, cyWu, 首次发布
* - V1.1.0, 2026.08.24, cyWu, 停转反转刹车;去掉限位脚
* - V1.3.0, 2026.08.24, cyWu, 电机改 MCPWM 占空比降速
* - V1.4.0, 2026.08.24, cyWu, 增加按占空比驱动,供玩法变速
******************************************************************************/
#include "system/includes.h"
#include "asm/gpio.h"
#include "asm/adc_api.h"
#include "asm/charge.h"
#include "asm/mcpwm.h"
#include "bsp_hw.h"
#define LOG_TAG_CONST APP
#define LOG_TAG "[BSP_HW]"
#define LOG_ERROR_ENABLE
#define LOG_INFO_ENABLE
#include "debug.h"
static uint8_t s_initialized;
static BspMotorDir_t s_motor_dir;
static BspMotorDir_t s_motor_pending;
static uint16_t s_motor_duty;
static uint16_t s_pending_duty;
static uint16_t s_brake_ms;
static u32 s_brake_t0;
extern u32 timer_get_ms(void);
#if (BOARD_LED_ENABLE || BOARD_MOTOR_ENABLE)
/**
* @brief 配置 GPIO 为推挽输出
* @param pin GPIO 编号
* @param value 输出初值
* @return 无
*/
static void bsp_pin_output(u32 pin, int value)
{
gpio_set_pull_up(pin, 0);
gpio_set_pull_down(pin, 0);
gpio_set_die(pin, 1);
gpio_direction_output(pin, value);
}
#endif
#if (BOARD_KEY_ENABLE || BOARD_CHG_ENABLE)
/**
* @brief 配置 GPIO 为数字输入(可内部上拉)
* @param pin GPIO 编号
* @param pull_up 1=内部上拉,0=不上拉
* @return 无
*/
static void bsp_pin_input(u32 pin, int pull_up)
{
gpio_direction_output(pin, 1);
gpio_set_direction(pin, 1);
gpio_set_pull_down(pin, 0);
gpio_set_pull_up(pin, pull_up ? 1 : 0);
gpio_set_die(pin, 1);
}
#endif
#if BOARD_MOTOR_ENABLE
/**
* @brief 初始化 INA/INB 两路 MCPWM,初始占空比 0(停转)
* @return 无
*/
static void bsp_motor_pwm_init(void)
{
struct pwm_platform_data pwm;
gpio_set_pull_up(BOARD_MOTOR_INA_PIN, 0);
gpio_set_pull_down(BOARD_MOTOR_INA_PIN, 0);
gpio_set_die(BOARD_MOTOR_INA_PIN, 1);
gpio_set_pull_up(BOARD_MOTOR_INB_PIN, 0);
gpio_set_pull_down(BOARD_MOTOR_INB_PIN, 0);
gpio_set_die(BOARD_MOTOR_INB_PIN, 1);
pwm.pwm_aligned_mode = pwm_edge_aligned;
pwm.frequency = BOARD_MOTOR_PWM_HZ;
pwm.duty = 0;
pwm.l_pin = (u8) - 1;
pwm.complementary_en = 0;
pwm.pwm_ch_num = pwm_ch0;
pwm.h_pin = BOARD_MOTOR_INA_PIN;
mcpwm_init(&pwm);
pwm.pwm_ch_num = pwm_ch1;
pwm.h_pin = BOARD_MOTOR_INB_PIN;
mcpwm_init(&pwm);
mcpwm_set_duty(pwm_ch0, 0);
mcpwm_set_duty(pwm_ch1, 0);
log_info("motor pwm %uHz duty=%u/10000\n",
(unsigned)BOARD_MOTOR_PWM_HZ, (unsigned)BOARD_MOTOR_PWM_DUTY);
}
/**
* @brief 立刻改 INA/INB PWM。运转脚输出 duty,另一脚 0%STOP=两路 0%
* @param dir 目标方向
* @param duty 占空比 0~10000
* @return 无
*/
static void bsp_motor_gpio(BspMotorDir_t dir, uint16_t duty)
{
u16 ina_duty = 0;
u16 inb_duty = 0;
if (duty > 10000) {
duty = 10000;
}
if (dir == BSP_MOTOR_IN) {
if (BOARD_MOTOR_IN_INA_HIGH) {
ina_duty = duty;
} else {
inb_duty = duty;
}
} else if (dir == BSP_MOTOR_OUT) {
if (BOARD_MOTOR_IN_INA_HIGH) {
inb_duty = duty;
} else {
ina_duty = duty;
}
}
mcpwm_set_duty(pwm_ch0, ina_duty);
mcpwm_set_duty(pwm_ch1, inb_duty);
}
#endif
/**
* @brief 初始化 GPIO / 充电 ADC
* @return BSP_HW_OK=成功
*/
BspHw_Ret_t bsp_hw_init(void)
{
if (s_initialized) {
return BSP_HW_OK;
}
#if BOARD_LED_ENABLE
bsp_pin_output(BOARD_LED_RED_PIN, !BOARD_LED_ON_LEVEL);
bsp_pin_output(BOARD_LED_GREEN_PIN, !BOARD_LED_ON_LEVEL);
#endif
#if BOARD_KEY_ENABLE
bsp_pin_input(BOARD_KEY_PIN, 1);
#endif
#if BOARD_CHG_ENABLE
/* PORTG 作数字输入必须开 dieh,否则读不到 ME4054 CHG */
gpio_disable_fun_output_port(BOARD_CHG_PIN);
gpio_set_pull_up(BOARD_CHG_PIN, 0);
gpio_set_pull_down(BOARD_CHG_PIN, 0);
gpio_set_die(BOARD_CHG_PIN, 1);
gpio_set_dieh(BOARD_CHG_PIN, 1);
gpio_direction_input(BOARD_CHG_PIN);
adc_add_sample_ch(AD_CH_LDO5V);
adc_set_sample_freq(AD_CH_LDO5V, 500);
#endif
#if BOARD_MOTOR_ENABLE
bsp_motor_pwm_init();
s_motor_dir = BSP_MOTOR_STOP;
s_motor_pending = BSP_MOTOR_STOP;
s_motor_duty = 0;
s_pending_duty = 0;
s_brake_ms = 0;
#endif
s_initialized = 1;
log_info("hw init led=%d key=%d chg=%d motor=%d\n",
BOARD_LED_ENABLE, BOARD_KEY_ENABLE, BOARD_CHG_ENABLE,
BOARD_MOTOR_ENABLE);
return BSP_HW_OK;
}
/**
* @brief 查询板级硬件是否已初始化
* @return BSP_HW_OK=已初始化,BSP_HW_ERR_NOT_INIT=未初始化
*/
BspHw_Ret_t bsp_hw_get_status(void)
{
return s_initialized ? BSP_HW_OK : BSP_HW_ERR_NOT_INIT;
}
/**
* @brief 红灯开关
* @param on 1=亮,0=灭
* @return 无
*/
void bsp_led_red_set(uint8_t on)
{
#if BOARD_LED_ENABLE
gpio_direction_output(BOARD_LED_RED_PIN, on ? BOARD_LED_ON_LEVEL : !BOARD_LED_ON_LEVEL);
#else
(void)on;
#endif
}
/**
* @brief 绿灯开关
* @param on 1=亮,0=灭
* @return 无
*/
void bsp_led_green_set(uint8_t on)
{
#if BOARD_LED_ENABLE
gpio_direction_output(BOARD_LED_GREEN_PIN, on ? BOARD_LED_ON_LEVEL : !BOARD_LED_ON_LEVEL);
#else
(void)on;
#endif
}
/**
* @brief 红绿灯全灭
* @return 无
*/
void bsp_led_all_off(void)
{
bsp_led_red_set(0);
bsp_led_green_set(0);
}
/**
* @brief 设置电机方向。STOP 时若正在转,先反转刹车再滑行
* @param dir 收绳 / 放绳 / 停转
* @return 无
*/
void bsp_motor_set(BspMotorDir_t dir)
{
bsp_motor_set_pwm(dir, (dir == BSP_MOTOR_STOP) ? 0 : BOARD_MOTOR_PWM_DUTY);
}
/**
* @brief 设置电机方向与 PWM 占空比
* @param dir 收绳 / 放绳 / 停转
* @param duty 占空比 0~10000STOP 时按 0 处理
* @return 无
*/
void bsp_motor_set_pwm(BspMotorDir_t dir, uint16_t duty)
{
#if !BOARD_MOTOR_ENABLE
(void)dir;
(void)duty;
return;
#else
if (duty > 10000) {
duty = 10000;
}
if (dir == BSP_MOTOR_STOP) {
duty = 0;
}
/* 同向只改占空比:直接改 PWM,不走换向死区 */
if (dir == s_motor_dir && s_brake_ms == 0) {
if (duty == s_motor_duty) {
return;
}
s_motor_duty = duty;
s_motor_pending = dir;
s_pending_duty = duty;
bsp_motor_gpio(dir, duty);
return;
}
/* 已经在反转刹车等到停,忽略重复 STOP */
if (dir == BSP_MOTOR_STOP && s_motor_pending == BSP_MOTOR_STOP && s_brake_ms) {
return;
}
/* 正在转时要停:先反向驱动再滑行,短接对此驱动无效 */
if (dir == BSP_MOTOR_STOP
&& (s_motor_dir == BSP_MOTOR_IN || s_motor_dir == BSP_MOTOR_OUT)) {
BspMotorDir_t rev = (s_motor_dir == BSP_MOTOR_OUT) ? BSP_MOTOR_IN : BSP_MOTOR_OUT;
uint16_t brake_duty = s_motor_duty ? s_motor_duty : BOARD_MOTOR_PWM_DUTY;
bsp_motor_gpio(rev, brake_duty);
s_motor_dir = rev;
s_motor_duty = brake_duty;
s_motor_pending = BSP_MOTOR_STOP;
s_pending_duty = 0;
s_brake_ms = BOARD_MOTOR_STOP_BRAKE_MS;
s_brake_t0 = timer_get_ms();
log_info("motor rev-brake %ums duty=%u\n",
(unsigned)BOARD_MOTOR_STOP_BRAKE_MS, (unsigned)brake_duty);
return;
}
/* 换向:先松开再输出,避免 H 桥直通 */
if (dir != BSP_MOTOR_STOP && s_motor_dir != BSP_MOTOR_STOP && dir != s_motor_dir) {
bsp_motor_gpio(BSP_MOTOR_STOP, 0);
s_motor_pending = dir;
s_pending_duty = duty;
s_brake_ms = BOARD_MOTOR_REVERSE_MS;
s_brake_t0 = timer_get_ms();
s_motor_dir = BSP_MOTOR_STOP;
s_motor_duty = 0;
return;
}
s_brake_ms = 0;
s_motor_dir = dir;
s_motor_pending = dir;
s_motor_duty = duty;
s_pending_duty = duty;
bsp_motor_gpio(dir, duty);
#endif
}
/**
* @brief 推进换向死区与停转反转刹车,按真实毫秒计时
* @return 无
*/
void bsp_motor_brake_tick(void)
{
#if !BOARD_MOTOR_ENABLE
return;
#else
if (s_brake_ms == 0) {
return;
}
if ((timer_get_ms() - s_brake_t0) < s_brake_ms) {
return;
}
s_brake_ms = 0;
s_motor_dir = s_motor_pending;
s_motor_duty = s_pending_duty;
bsp_motor_gpio(s_motor_dir, s_motor_duty);
#endif
}
/**
* @brief 读取按键电平
* @return 1=按下,0=未按下
*/
uint8_t bsp_key_is_pressed(void)
{
#if BOARD_KEY_ENABLE
return (uint8_t)(gpio_read(BOARD_KEY_PIN) == BOARD_KEY_ACTIVE_LEVEL);
#else
return 0;
#endif
}
/**
* @brief 读取 ME4054 CHG 脚:充电中为低
* @return 1=充电中,0=未充电
*/
uint8_t bsp_chg_is_low(void)
{
#if BOARD_CHG_ENABLE
return (uint8_t)(gpio_read(BOARD_CHG_PIN) == BOARD_CHG_CHARGING_LEVEL);
#else
return 0;
#endif
}
/**
* @brief 读取电池电压
* @return 电池电压,单位 mV
*/
uint16_t bsp_vbat_mv(void)
{
return (uint16_t)(adc_get_voltage(AD_CH_VBAT) * 4);
}
/**
* @brief 读取 5V 口电压,用于判断 USB
* @return VPWR 电压,单位 mV
*/
uint16_t bsp_vpwr_mv(void)
{
return (uint16_t)(adc_get_voltage(AD_CH_LDO5V) * 4);
}
/**
* @brief USB 是否在位(以 ADC 为主,比较器为辅)
* @return 1=插入,0=未插入
*/
uint8_t bsp_vpwr_is_online(void)
{
#if BOARD_CHG_ENABLE
uint16_t mv = bsp_vpwr_mv();
/* 以 ADC 为准:拔电后比较器可能仍为 1,但电压已经掉到几百 mV */
if (mv >= BOARD_VPWR_ONLINE_MV) {
return 1;
}
if (mv <= BOARD_VPWR_OFF_MV) {
return 0;
}
if (get_ldo5v_online_hw() || get_lvcmp_det()) {
return 1;
}
return 0;
#else
return 0;
#endif
}
/**
* @brief 进深睡前把电机 PWM 关掉并拉低,灯全灭
* @return 无
*/
void bsp_hw_enter_sleep_io(void)
{
bsp_motor_set(BSP_MOTOR_STOP);
#if BOARD_MOTOR_ENABLE
mcpwm_set_duty(pwm_ch0, 0);
mcpwm_set_duty(pwm_ch1, 0);
mcpwm_close(pwm_ch0);
mcpwm_close(pwm_ch1);
gpio_och_disable_output_signal(BOARD_MOTOR_INA_PIN, OUTPUT_CH_SIGNAL_MC_PWM0_H);
gpio_och_disable_output_signal(BOARD_MOTOR_INB_PIN, OUTPUT_CH_SIGNAL_MC_PWM1_H);
gpio_direction_output(BOARD_MOTOR_INA_PIN, 0);
gpio_direction_output(BOARD_MOTOR_INB_PIN, 0);
#endif
bsp_led_all_off();
}