XCP on classic CAN — co se mění

Příklad sestavuje obraz pro CAN presetem DebugCan; vše v této kapitole je to, co tento preset mění oproti Debug (obraz pro TCP popsaný v kapitole Integrace: XCP on TCP). Periferie ST se jmenuje FDCAN; SDK ji používá v režimu classic CAN (rámce 8 B, bez přepínání bitové rychlosti) — dále jen classic CAN.

Stejné a odlišné

Stejné jako u TCPOdlišné na CAN
zdroje enginu a qfw_xcp.hkodek transportu přeložený do enginu: qfw_xcptl_can.c místo qfw_xcptl.c (volí QFW_XCP_TRANSPORT=can, bez rámcování na sběrnici, MAX_CTO = MAX_DTO = 8)
port hodin a kontrakt hodinglue: glue/freertos_can/xcp_can_glue.c místo glue/freertos_lwip/xcp_sdk_glue.c
identita (project_name, epk), log, kritická sekce, paměť frontyport: port/fdcan (wrapper FDCAN) navíc k port/clock; lwIP není potřeba
eventy: qfw_xcp_create_event / qfw_xcp_trigger_event, daqId v QInsightkonfigurace glue: tQfwXcpCanGlueConfig (master_id, slave_id, extended_ids, bitrate_kbps) místo port
tři volání ve freertos.cvstup pro příjem: qfw_xcp_rx_can_frame(data, dlc) místo qfw_xcp_rx(bytes, len)
pravidla pro proměnné a nástroje pro adresy#if defined(QFW_XCP_TRANSPORT_CAN) v integračním souboru vybírá hlavičku a konfiguraci glue

Jeden obraz firmwaru nese právě jeden transport (symboly obou variant enginu záměrně kolidují).

Volba sestavení

cmake --preset DebugCan nastaví QFW_XCP_TRANSPORT=can (CMakePresets.json); ve vlastním projektu předejte při konfiguraci -DQFW_XCP_TRANSPORT=can. Úryvek CMake z kapitoly o TCP pak přidá ${QFW_XCP_GLUE_FREERTOS_CAN_SOURCES}, ${QFW_XCP_PORT_FDCAN_SOURCES}, odpovídající include adresáře a definice QFW_XCP_TRANSPORT_CAN (pro váš integrační soubor) a ${QFW_XCP_PORT_FDCAN_DEFINES} (= HAL_FDCAN_MODULE_ENABLED).

Port FDCAN a váš projekt CubeMX

port/fdcan/fdcan_classic.c uvádí FDCAN1 do provozu kompletně v kódu: kernel clock FDCAN z HSE (8 MHz na Nucleo, tabulka bit timingu je spočítána pro něj), GPIO PD0 = FDCAN1_RX / PD1 = FDCAN1_TX (AF9), klasický formát rámce, rozložení message RAM (RX FIFO0 hloubky 32, TX FIFO hloubky 16), jeden akceptační filtr propouštějící do RX FIFO0 pouze id mastera (vše ostatní i všechny remote rámce odmítnuty), provoz pollingem bez přerušení. API: FdcanClassic_Init(&cfg), FdcanClassic_Receive(data, &dlc), FdcanClassic_Transmit(data, len), FdcanClassic_RecoverBusOff(). Podporované bitové rychlosti: 125, 250, 500, 1000 kbit/s.

port/fdcan/hal/ obsahuje HAL driver FDCAN od ST (STM32Cube FW_H7 V1.13.0, beze změn, BSD-3-Clause, viz port/fdcan/ORIGIN.md). Příklad FDCAN ve svém .ioc nezapíná: periferii uvádí do provozu výhradně FdcanClassic_Init (hodiny, GPIO, filtr, message RAM) a HAL driver pochází z port/fdcan/hal, protože CubeMX jej pro nezapnutou periferii do Drivers/ nekopíruje. Ve svém projektu postupujte stejně: FDCAN v .ioc nezapínejte, do cíle přidejte port/fdcan/fdcan_classic.c a port/fdcan/hal/stm32h7xx_hal_fdcan.c s include adresáři a HAL_FDCAN_MODULE_ENABLED (přesně to dělají proměnné QFW_XCP_PORT_FDCAN_SOURCES, QFW_XCP_PORT_FDCAN_INCLUDE_DIRS, QFW_XCP_PORT_FDCAN_DEFINES z cmake/qfw_xcp.cmake, viz CMakeLists.txt příkladu). Toto je konfigurace ověřená na NUCLEO-H723ZG s QInsight.

Integrační soubor a glue

Větev CAN v app/xcp_server.c příkladu:

#if defined(QFW_XCP_TRANSPORT_CAN)
#include "xcp_can_glue.h"
#define QFW_XCP_CAN_MASTER_ID 0x200U     /* QInsight default: master -> slave */
#define QFW_XCP_CAN_SLAVE_ID 0x201U      /* slave -> master */
#define QFW_XCP_CAN_BITRATE_KBPS 500U
#endif
...
    tQfwXcpCanGlueConfig config = {
        .project_name = QFW_XCP_PROJECT_NAME,
        .epk = QFW_XCP_EPK,
        .master_id = QFW_XCP_CAN_MASTER_ID,
        .slave_id = QFW_XCP_CAN_SLAVE_ID,
        .extended_ids = false,           /* 11-bit identifiers */
        .bitrate_kbps = QFW_XCP_CAN_BITRATE_KBPS,
        .log_level = 2U,
        .get_clock_us = QfwXcpClockUs,
    };
    if (!QfwXcpCanGlue_Init(&config))
    {
        return false;
    }

QfwXcpCanGlue_Init (glue/freertos_can/xcp_can_glue.c) vytvoří rekurzivní mutex, inicializuje engine (3 segmenty fronty), zavolá FdcanClassic_Init s rx_id = master_id, tx_id = slave_id a vytvoří server task QfwXcpCanGlue (zásobník 4 KB, priorita idle+2). Smyčka úlohy běží každou 1 ms:

drain RX FIFO0  ->  qfw_xcp_rx_can_frame() per frame   (one frame = one XCP packet, no framing)
qfw_xcp_poll()  ->  GlueTransmit -> FdcanClassic_Transmit (one call = one frame on slave_id, len 8, zero padded)
FdcanClassic_RecoverBusOff() true?  ->  qfw_xcp_on_transport_reset()   (the only transport reset on CAN)
vTaskDelay(1)

Neexistuje spojení ani proud bajtů: poškozený rámec engine zahodí a nic se nemusí znovu synchronizovat; plné TX FIFO je čistý backpressure (transmit vrátí false, engine rámec zopakuje při příštím pollu). RX FIFO hloubky 32 pojme více než 8 ms plně zatížené sběrnice 500 kbit/s, kadence 1 ms má tedy rezervu.

Zapojení (NUCLEO-H723ZG)

FDCAN1 používá PD0 = FDCAN1_RX a PD1 = FDCAN1_TX (AF9). Nucleo nemá CAN transceiver — připojte externí 3,3V transceiver (např. SN65HVD230, TJA1051T/3): jeho TXD na PD1, RXD na PD0, VCC 3,3 V, společná GND, CANH/CANL na sběrnici se 120Ω zakončením na obou koncích kabelu (strana PCAN-USB obvykle jedno poskytuje).

Strana QInsight

Driver PEAK CAN Adapter (PCAN-USB; bitrate=500000 (bit/s), deviceId = ID vašeho adaptéru), protokol XCP on CAN s masterId=0x200, slaveId=0x201, extendedIds=false. Proměnné, události a daqId se konfigurují přesně jako u TCP. Hodnoty delší než jeden rámec QInsight řetězí automaticky: čtení po nejvýše 7 B (SHORT_UPLOAD a dále UPLOAD), zápis SET_MTA a pak DOWNLOAD po nejvýše 6 B — 8bajtová hodnota se tak čte jako 7+1 B a zapisuje jako 6+2 B; se slavem s block módem jde 8bajtová hodnota jedním UPLOAD burstem 7+1 B. Ukázkový projekt Qenex_CAN_XCP_NucleoH723_Maps_FreeRTOS.qproj popisuje kapitola XCP on CAN na NUCLEO-H723ZG.

Dimenzování a propustnost

  • Vysílací fronta: 2–4 segmenty (QFW_XCP_QUEUE_MEM_SIZE(3) = 4632 B je výchozí hodnota glue). CAN přenese nejvýše 6 datových bajtů na DAQ rámec při ~4000 rámcích/s (500 kbit/s, celá sběrnice) — větší fronta jen prohlubuje zpoždění, propustnost zvýšit nemůže.
  • Kapacita DAQ na rámec: identifikační pole má 2 bajty (číslo ODT + DAQ); s časovými značkami slave (daqTimestamps=slave) nese první ODT listu navíc časovou značku DWORD → 2 B dat v ODT0, 6 B v každém dalším ODT. S daqTimestamps=master nesou všechny ODT 6 B.
  • Indikace ztráty: přetečení vysílací fronty (na CAN snadno dosažitelné ambiciózní sadou DAQ) se podle standardu XCP hlásí nastavením MSB čísla ODT v prvním DTO po přetečení — QInsight ztráty zobrazí; zahazují se celé rámce, data se nikdy nepoškodí.
  • Neimplementováno (podle standardu volitelné, QInsight nepoužívá): GET_SLAVE_ID, GET_DAQ_ID, SET_DAQ_ID (ERR_CMD_UNKNOWN).

Dále

Kontrakt enginu — pravidla, která za glue stojí; Řešení potíží — řádky pro CAN v tabulce příznaků.