Mamba F722S MK2 does not expose PB12/PB13 externally. Waveshare CAN module is wired to the SCL (PB8) and SDA (PB9) header pads. Changes in can_driver_init(): - Drop __HAL_RCC_CAN2_CLK_ENABLE() — CAN1 needs no slave clock - GPIO: GPIO_PIN_12/13 → GPIO_PIN_8/9, GPIO_AF9_CAN2 → GPIO_AF9_CAN1 - Instance: CAN2 → CAN1 - Filter bank: 14 → 0 (CAN1 master banks start at 0; bank 14 is the CAN2 slave-start boundary, unused here) I2C1 is free: BME280 has been moved to I2C2 (PB10/PB11), so PB8/PB9 are available for CAN1 without any peripheral conflict. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
82 lines
2.7 KiB
C
82 lines
2.7 KiB
C
#ifndef CAN_DRIVER_H
|
||
#define CAN_DRIVER_H
|
||
|
||
#include <stdint.h>
|
||
#include <stdbool.h>
|
||
|
||
/* CAN bus driver for BLDC motor controllers (Issue #597)
|
||
* CAN1 on PB8 (RX, AF9) / PB9 (TX, AF9) at 500 kbps (Issue #676 remap)
|
||
* APB1 = 54 MHz: PSC=6, BS1=13tq, BS2=4tq, SJW=1tq → 18 tq/bit = 500 kbps
|
||
*/
|
||
|
||
/* Node IDs */
|
||
#define CAN_NUM_MOTORS 2u
|
||
#define CAN_NODE_LEFT 0u
|
||
#define CAN_NODE_RIGHT 1u
|
||
|
||
/* CAN frame IDs */
|
||
#define CAN_ID_VEL_CMD_BASE 0x100u /* TX: 0x100 + node_id — velocity/torque command */
|
||
#define CAN_ID_ENABLE_CMD_BASE 0x110u /* TX: 0x110 + node_id — enable/disable */
|
||
#define CAN_ID_FEEDBACK_BASE 0x200u /* RX: 0x200 + node_id — position/velocity/current */
|
||
|
||
/* Filter: accept standard IDs 0x200–0x21F */
|
||
#define CAN_FILTER_STDID 0x200u
|
||
#define CAN_FILTER_MASK 0x7E0u
|
||
|
||
/* Bit timing (500 kbps @ 54 MHz APB1) */
|
||
#define CAN_PRESCALER 6u
|
||
|
||
/* TX rate */
|
||
#define CAN_TX_RATE_HZ 100u
|
||
|
||
/* Node alive timeout */
|
||
#define CAN_NODE_TIMEOUT_MS 100u
|
||
|
||
/* TX command frame (8 bytes payload, DLC=4 for vel cmd) */
|
||
typedef struct {
|
||
int16_t velocity_rpm; /* target RPM (+/- = fwd/rev) */
|
||
int16_t torque_x100; /* torque limit × 100 (0 = unlimited) */
|
||
} can_cmd_t;
|
||
|
||
/* RX feedback frame (DLC=8) */
|
||
typedef struct {
|
||
int16_t velocity_rpm; /* actual RPM */
|
||
int16_t current_ma; /* phase current in mA */
|
||
int16_t position_x100; /* position × 100 (degrees or encoder counts) */
|
||
int8_t temperature_c; /* controller temperature °C */
|
||
uint8_t fault; /* fault flags (0 = healthy) */
|
||
uint32_t last_rx_ms; /* HAL_GetTick() at last valid frame */
|
||
} can_feedback_t;
|
||
|
||
/* Bus statistics */
|
||
typedef struct {
|
||
uint32_t tx_count; /* frames transmitted */
|
||
uint32_t rx_count; /* frames received */
|
||
uint16_t err_count; /* HAL-level errors */
|
||
uint8_t bus_off; /* 1 = bus-off state */
|
||
uint8_t _pad;
|
||
} can_stats_t;
|
||
|
||
/* Initialise CAN2 peripheral, GPIO, and filter bank 14 */
|
||
void can_driver_init(void);
|
||
|
||
/* Send velocity+torque command to one node */
|
||
void can_driver_send_cmd(uint8_t node_id, const can_cmd_t *cmd);
|
||
|
||
/* Send enable/disable command to one node */
|
||
void can_driver_send_enable(uint8_t node_id, bool enable);
|
||
|
||
/* Copy latest feedback snapshot (returns false if node never heard from) */
|
||
bool can_driver_get_feedback(uint8_t node_id, can_feedback_t *out);
|
||
|
||
/* Returns true if node has been heard within CAN_NODE_TIMEOUT_MS */
|
||
bool can_driver_is_alive(uint8_t node_id, uint32_t now_ms);
|
||
|
||
/* Copy bus statistics snapshot */
|
||
void can_driver_get_stats(can_stats_t *out);
|
||
|
||
/* Drain RX FIFO0; call every main-loop tick */
|
||
void can_driver_process(void);
|
||
|
||
#endif /* CAN_DRIVER_H */
|