Implements binary command protocol on UART5 (PC12/PD2) at 115200 baud for Jetson→STM32 communication. Frame: STX+LEN+CMD+PAYLOAD+CRC8+ETX. Commands: SET_VELOCITY (RPM direct to CAN), GET_STATUS, SET_PID, ESTOP, CLEAR_ESTOP. DMA1_Stream0_Channel4 circular 256-byte RX ring. ACK/NACK inline; STATUS pushed at 10 Hz. Heartbeat timeout 500 ms (UART_PROT_HB_TIMEOUT_MS). NOTE: Spec requested USART1 @ 115200; USART1 occupied by JLink @ 921600. Implemented on UART5 instead; note in code comments. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
97 lines
4.4 KiB
C
97 lines
4.4 KiB
C
#ifndef UART_PROTOCOL_H
|
||
#define UART_PROTOCOL_H
|
||
|
||
/*
|
||
* uart_protocol.h — UART command protocol for Jetson-STM32 communication (Issue #629)
|
||
*
|
||
* Frame format:
|
||
* [STX][LEN][CMD][PAYLOAD...][CRC8][ETX]
|
||
* 0x02 1B 1B 0-12 B 1B 0x03
|
||
*
|
||
* CRC8-SMBUS: poly=0x07, init=0x00, computed over CMD+PAYLOAD bytes.
|
||
*
|
||
* Physical layer: UART5 (PC12=TX / PD2=RX), GPIO_AF8_UART5, 115200 baud, no hw flow.
|
||
* NOTE: Spec requested USART1 @ 115200, but USART1 is occupied by JLink @ 921600.
|
||
* Implemented on UART5 instead; Jetson must connect to PC12/PD2.
|
||
*
|
||
* DMA: DMA1_Stream0_Channel4, circular 256-byte ring buffer.
|
||
* Heartbeat: if no frame received in UART_PROT_HB_TIMEOUT_MS (500 ms), Jetson is
|
||
* considered lost; caller must handle estop if needed.
|
||
*/
|
||
|
||
#include <stdint.h>
|
||
#include <stdbool.h>
|
||
|
||
/* ── Frame delimiters ─────────────────────────────────────────────────────── */
|
||
#define UPROT_STX 0x02u
|
||
#define UPROT_ETX 0x03u
|
||
|
||
/* ── Command IDs (host → STM32) ───────────────────────────────────────────── */
|
||
#define UCMD_SET_VELOCITY 0x01u /* payload: int16 left_rpm, int16 right_rpm (4 B) */
|
||
#define UCMD_GET_STATUS 0x02u /* payload: none */
|
||
#define UCMD_SET_PID 0x03u /* payload: float kp, float ki, float kd (12 B) */
|
||
#define UCMD_ESTOP 0x04u /* payload: none */
|
||
#define UCMD_CLEAR_ESTOP 0x05u /* payload: none */
|
||
|
||
/* ── Response IDs (STM32 → host) ──────────────────────────────────────────── */
|
||
#define URESP_ACK 0x80u /* payload: 1 B — echoed CMD */
|
||
#define URESP_NACK 0x81u /* payload: 2 B — CMD, error_code */
|
||
#define URESP_STATUS 0x82u /* payload: sizeof(uart_prot_status_t) = 8 B */
|
||
|
||
/* ── NACK error codes ─────────────────────────────────────────────────────── */
|
||
#define UERR_BAD_CRC 0x01u
|
||
#define UERR_BAD_LEN 0x02u
|
||
#define UERR_BAD_ETX 0x03u
|
||
#define UERR_ESTOP 0x04u /* command rejected — estop active */
|
||
#define UERR_DISARMED 0x05u /* velocity rejected — not armed */
|
||
|
||
/* ── STATUS payload (URESP_STATUS, 8 bytes packed) ───────────────────────── */
|
||
typedef struct __attribute__((packed)) {
|
||
int16_t pitch_x10; /* pitch angle ×10 deg (balance controller) */
|
||
int16_t motor_cmd; /* ESC motor command -1000..+1000 */
|
||
uint16_t vbat_mv; /* battery voltage in mV */
|
||
uint8_t balance_state; /* BalanceState enum (0=DISARMED, 1=ARMED, …) */
|
||
uint8_t estop_active; /* non-zero if remote estop is latched */
|
||
} uart_prot_status_t;
|
||
|
||
/* ── Shared state (read by main.c) ────────────────────────────────────────── */
|
||
typedef struct {
|
||
volatile uint8_t vel_updated; /* 1 when SET_VELOCITY received */
|
||
volatile int16_t left_rpm;
|
||
volatile int16_t right_rpm;
|
||
|
||
volatile uint8_t pid_updated; /* 1 when SET_PID received */
|
||
volatile float pid_kp;
|
||
volatile float pid_ki;
|
||
volatile float pid_kd;
|
||
|
||
volatile uint8_t estop_req; /* 1 on UCMD_ESTOP */
|
||
volatile uint8_t estop_clear_req; /* 1 on UCMD_CLEAR_ESTOP */
|
||
|
||
volatile uint32_t last_rx_ms; /* HAL_GetTick() of last valid frame */
|
||
} UartProtState;
|
||
|
||
extern UartProtState uart_prot_state;
|
||
|
||
/* ── API ───────────────────────────────────────────────────────────────────── */
|
||
|
||
/**
|
||
* uart_protocol_init() — configure UART5 + DMA, start circular receive.
|
||
* Must be called once during system init, before main loop.
|
||
*/
|
||
void uart_protocol_init(void);
|
||
|
||
/**
|
||
* uart_protocol_process() — drain DMA ring buffer, parse frames, dispatch commands.
|
||
* Call once per main loop iteration (every ~1 ms).
|
||
*/
|
||
void uart_protocol_process(void);
|
||
|
||
/**
|
||
* uart_protocol_send_status() — build and TX a URESP_STATUS frame.
|
||
* @param s Pointer to status payload to send.
|
||
*/
|
||
void uart_protocol_send_status(const uart_prot_status_t *s);
|
||
|
||
#endif /* UART_PROTOCOL_H */
|