Archive STM32 firmware to legacy/stm32/: - src/, include/, lib/USB_CDC/, platformio.ini, test stubs, flash_firmware.py - test/test_battery_adc.c, test_hw_button.c, test_pid_schedule.c, test_vesc_can.c, test_can_watchdog.c - USB_CDC_BUG.md Rename: stm32_protocol → esp32_protocol, mamba_protocol → balance_protocol, stm32_cmd_node → esp32_cmd_node, stm32_cmd_params → esp32_cmd_params, stm32_cmd.launch.py → esp32_cmd.launch.py, test_stm32_protocol → test_esp32_protocol, test_stm32_cmd_node → test_esp32_cmd_node Content cleanup across all files: - Mamba F722S → ESP32-S3 BALANCE - BlackPill → ESP32-S3 IO - STM32F722/F7xx → ESP32-S3 - stm32Mode/Version/Port → esp32Mode/Version/Port - STM32 State/Mode labels → ESP32 State/Mode - Jetson Nano → Jetson Orin Nano Super - /dev/stm32 → /dev/esp32 - stm32_bridge → esp32_bridge - STM32 HAL → ESP-IDF docs/SALTYLAB.md: - Update "Drone FC Details" to describe ESP32-S3 BALANCE board (Waveshare ESP32-S3 Touch LCD 1.28) - Replace verbose "Self-Balancing Control" STM32 section with brief note pointing to SAUL-TEE-SYSTEM-REFERENCE.md TEAM.md: Update Embedded Firmware Engineer role to ESP32-S3 / ESP-IDF No new functionality — cleanup only. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
122 lines
3.9 KiB
C
122 lines
3.9 KiB
C
#ifndef MOTOR_CURRENT_H
|
|
#define MOTOR_CURRENT_H
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
|
|
/*
|
|
* motor_current — ADC-based motor current monitoring and overload protection
|
|
* for Issue #584.
|
|
*
|
|
* Hardware:
|
|
* ADC3 IN13 (PC3, ADC_CURR_PIN) is already sampled by battery_adc.c via
|
|
* DMA2_Stream0 circular. This module reads battery_adc_get_current_ma()
|
|
* each tick rather than running a second ADC, since total discharge current
|
|
* on this single-motor balance bot equals motor current plus ~30 mA overhead.
|
|
*
|
|
* Behaviour:
|
|
* MC_NORMAL : current_ma < MOTOR_CURR_SOFT_MA — full output
|
|
* MC_SOFT_LIMIT : current_ma in [SOFT_MA, HARD_MA) — linear PWM reduction
|
|
* MC_COOLDOWN : hard cutoff latched after HARD_MA sustained for
|
|
* MOTOR_CURR_OVERLOAD_MS (2 s) — zero output for
|
|
* MOTOR_CURR_COOLDOWN_MS (10 s), then MC_NORMAL
|
|
*
|
|
* Soft limit formula (MC_SOFT_LIMIT):
|
|
* scale = (HARD_MA - current_ma) / (HARD_MA - SOFT_MA) [0..1]
|
|
* limited_cmd = (int16_t)(cmd * scale)
|
|
*
|
|
* Fault event:
|
|
* On each hard-cutoff trip, s_fault_count is incremented (saturates at 255)
|
|
* and motor_current_fault_pending() returns true for one main-loop tick so
|
|
* the caller can append a fault log entry.
|
|
*
|
|
* Main-loop integration (pseudo-code):
|
|
*
|
|
* void main_loop_tick(uint32_t now_ms) {
|
|
* battery_adc_tick(now_ms);
|
|
* motor_current_tick(now_ms);
|
|
*
|
|
* if (motor_current_fault_pending())
|
|
* fault_log_append(FAULT_MOTOR_OVERCURRENT);
|
|
*
|
|
* int16_t cmd = balance_pid_output();
|
|
* cmd = motor_current_apply_limit(cmd);
|
|
* motor_driver_update(&g_motor, cmd, steer, now_ms);
|
|
*
|
|
* motor_current_send_tlm(now_ms); // rate-limited to MOTOR_CURR_TLM_HZ
|
|
* }
|
|
*/
|
|
|
|
/* ---- Thresholds ---- */
|
|
#define MOTOR_CURR_HARD_MA 5000u /* 5 A — hard cutoff level */
|
|
#define MOTOR_CURR_SOFT_MA 4000u /* 4 A — soft-limit onset (80% of hard) */
|
|
#define MOTOR_CURR_OVERLOAD_MS 2000u /* sustained over HARD_MA before fault */
|
|
#define MOTOR_CURR_COOLDOWN_MS 10000u /* zero-output recovery period (ms) */
|
|
#define MOTOR_CURR_TLM_HZ 5u /* JLINK_TLM_MOTOR_CURRENT publish rate */
|
|
|
|
/* ---- State enum ---- */
|
|
typedef enum {
|
|
MC_NORMAL = 0,
|
|
MC_SOFT_LIMIT = 1,
|
|
MC_COOLDOWN = 2,
|
|
} MotorCurrentState;
|
|
|
|
/* ---- API ---- */
|
|
|
|
/*
|
|
* motor_current_init() — reset all state.
|
|
* Call once during system init, after battery_adc_init().
|
|
*/
|
|
void motor_current_init(void);
|
|
|
|
/*
|
|
* motor_current_tick(now_ms) — evaluate ADC reading, update state machine.
|
|
* Call from main loop after battery_adc_tick(), at any rate ≥ 10 Hz.
|
|
* Non-blocking (<1 µs).
|
|
*/
|
|
void motor_current_tick(uint32_t now_ms);
|
|
|
|
/*
|
|
* motor_current_apply_limit(cmd) — scale motor command by current-limit factor.
|
|
* MC_NORMAL: returns cmd unchanged.
|
|
* MC_SOFT_LIMIT: returns cmd scaled down linearly.
|
|
* MC_COOLDOWN: returns 0.
|
|
* Call after motor_current_tick() each loop iteration.
|
|
*/
|
|
int16_t motor_current_apply_limit(int16_t cmd);
|
|
|
|
/*
|
|
* motor_current_is_faulted() — true while in MC_COOLDOWN (output zeroed).
|
|
*/
|
|
bool motor_current_is_faulted(void);
|
|
|
|
/*
|
|
* motor_current_state() — current state machine state.
|
|
*/
|
|
MotorCurrentState motor_current_state(void);
|
|
|
|
/*
|
|
* motor_current_ma() — most recent ADC reading used by the state machine (mA).
|
|
*/
|
|
int32_t motor_current_ma(void);
|
|
|
|
/*
|
|
* motor_current_fault_count() — lifetime hard-cutoff trip counter (0..255).
|
|
*/
|
|
uint8_t motor_current_fault_count(void);
|
|
|
|
/*
|
|
* motor_current_fault_pending() — true for exactly one tick after a hard
|
|
* cutoff trip fires. Main loop should append a fault log entry and then the
|
|
* flag clears automatically on the next call.
|
|
*/
|
|
bool motor_current_fault_pending(void);
|
|
|
|
/*
|
|
* motor_current_send_tlm(now_ms) — transmit JLINK_TLM_MOTOR_CURRENT (0x86)
|
|
* frame to Jetson. Rate-limited to MOTOR_CURR_TLM_HZ; safe to call every tick.
|
|
*/
|
|
void motor_current_send_tlm(uint32_t now_ms);
|
|
|
|
#endif /* MOTOR_CURRENT_H */
|