Índice

Dominando la Capa Física y Timing de Bit en CAN y CAN-FD: Transceptores, Arbitraje y Cálculo de Cuantos de Tiempo


Introducción al Protocolo CAN y CAN-FD

El bus CAN (Controller Area Network), estandarizado bajo la norma ISO 11898, es la columna vertebral de las comunicaciones en tiempo real en la industria automotriz, robótica industrial y mecatrónica avanzadas. Diseñado por Robert Bosch GmbH en la década de 1980, este protocolo de comunicación serie síncrono y multimaestro destaca por su inmunidad al ruido electromagnético y su robustez determinista.

Con la evolución de los sistemas mecatrónicos modernos (vehículos autónomos, drivetrains híbridos y buses de datos de alta densidad), surgió la extensión CAN-FD (Flexible Data-rate) según ISO 11898-1:2015, permitiendo cargas útiles de hasta 64 bytes (en comparación con los 8 bytes del CAN Clásico) y velocidades de datos en la fase de payload superiores a 5 Mbps.


Capa Física: Niveles Tensiónales Diferenciales y Transceptores

El bus CAN utiliza un par trenzado no blindado para transmitir datos mediante señalización diferencial. Los dos cables se denominan CAN High (CAN_H) y CAN Low (CAN_L). La línea se termina en ambos extremos con resistencias de 120 Ω120\,\Omega acopladas en paralelo, resultando en una impedancia equivalente de bus de Rbus=60 ΩR_{bus} = 60\,\Omega.

Estados Lógicos: Dominante vs. Recesivo

En el protocolo CAN, la lógica de bus sigue una estructura de colector/drenador abierto implícita a nivel de transceptor:

  1. Estado Recesivo (1 lógico): Los transistores de salida del transceptor están desactivados. Las líneas CAN_H y CAN_L son llevadas al mismo nivel de tensión mediante la red de terminación.

    • VCAN_H≈2.5 VV_{CAN\_H} \approx 2.5\text{ V}
    • VCAN_L≈2.5 VV_{CAN\_L} \approx 2.5\text{ V}
    • Vdiff=VCAN_H−VCAN_L≈0 VV_{diff} = V_{CAN\_H} - V_{CAN\_L} \approx 0\text{ V} (Rango recesivo especificado: −0.5 V<Vdiff<0.5 V-0.5\text{ V} < V_{diff} < 0.5\text{ V}).
  2. Estado Dominante (0 lógico): El transceptor activa sus etapas de potencia conducidas (MOSFETs P y N), elevando CAN_H y reduciendo CAN_L.

    • VCAN_H≈3.5 VV_{CAN\_H} \approx 3.5\text{ V}
    • VCAN_L≈1.5 VV_{CAN\_L} \approx 1.5\text{ V}
    • Vdiff=VCAN_H−VCAN_L≈2.0 VV_{diff} = V_{CAN\_H} - V_{CAN\_L} \approx 2.0\text{ V} (Rango dominante especificado: 0.9 V<Vdiff<5.0 V0.9\text{ V} < V_{diff} < 5.0\text{ V}).
 Estado Dominante (0)                  Estado Recesivo (1)
  V_CAN_H = 3.5V  --------              V_CAN_H = 2.5V --------
                          \                                  /
                           \                                /
  V_CAN_L = 1.5V  --------              V_CAN_L = 2.5V --------
  V_diff = 2.0V                         V_diff = 0.0V

Si un nodo transmite un bit Dominante (0) mientras otro transmite un bit Recesivo (1), el bus adoptará mecánicamente el estado Dominante. Esta propiedad eléctrica es el fundamento del arbitraje no destructivo.


Arbitraje No Destructivo y Bit Stuffing

Acceso Mecánico por Bus Votado

El bus CAN utiliza CSMA/CR (Carrier Sense Multiple Access with Collision Resolution). Durante la fase de transmisión del Identificador de Trama (11 bits en CAN Estándar o 29 bits en CAN Extendido), todos los nodos que intentan transmitir leen continuamente el bus pin a pin a través del circuito de recepción RXD del transceptor.

  • Si un nodo transmite un bit recesivo (1) pero detecta un bit dominante (0) en la línea, deduce que un nodo con un ID de menor valor numérico (mayor prioridad) está transmitiendo.
  • El nodo pierde el arbitraje e inmediatamente conmuta su transmisor a modo de recepción pasiva sin interrumpir la trama en curso.

Regla de Relleno de Bits (Bit Stuffing)

Para garantizar la sincronización de reloj entre nodos sin requerir una línea de reloj explícita, se implementa la regla de relleno de bits: después de 5 bits consecutivos del mismo nivel lógico (dominante o recesivo), el controlador inserta automáticamente un bit complementario opuesto.


Sincronización y Configuración del Bit Timing

Un bit nominal en el bus CAN se divide en cuatro segmentos temporales discretos medidos en unidades fijas de tiempo llamadas Time Quanta (TqT_q):

Tq=BRPfsysT_q = \frac{\text{BRP}}{f_{sys}}

donde BRP\text{BRP} es el Baud Rate Prescaler y fsysf_{sys} es la frecuencia del reloj del controlador CAN.

Composición de la Trama Temporal de Bit

Nominal Bit Time=TSync_Seg+TProp_Seg+TPhase_Seg1+TPhase_Seg2\text{Nominal Bit Time} = T_{Sync\_Seg} + T_{Prop\_Seg} + T_{Phase\_Seg1} + T_{Phase\_Seg2}

  1. Sync_Seg: Siempre equivale a 1 Tq1\,T_q. Se utiliza para sincronizar los relojes de los distintos nodos. La transición de señal debe ocurrir dentro de este segmento.
  2. Prop_Seg: Compensa los retardos físicos de propagación de la señal en el cable y las latencias internas de los transceptores.
  3. Phase_Seg1 & Phase_Seg2: Absorben variaciones de fase causadas por la tolerancia del cristal o resonador. El punto de muestreo (Sample Point) se sitúa entre Phase_Seg1 y Phase_Seg2.

Sample Point (%)=TSync_Seg+TProp_Seg+TPhase_Seg1Nominal Bit Time×100\text{Sample Point (\%)} = \frac{T_{Sync\_Seg} + T_{Prop\_Seg} + T_{Phase\_Seg1}}{\text{Nominal Bit Time}} \times 100


Código de Ejemplo: Cálculo de Parámetros de Timing para CAN / CAN-FD en C++

El siguiente código simula la configuración matemática de los registros de timing para un controlador CAN-FD ajustando la tasa nominal (Nominal Bit Rate - NBR) y la tasa de datos (Data Bit Rate - DBR).

#include <iostream>
#include <cstdint>
#include <cmath>

struct CAN_BitTimingConfig {
    uint32_t brp;
    uint32_t prop_seg;
    uint32_t phase_seg1;
    uint32_t phase_seg2;
    uint32_t sjw;
    double actual_baudrate;
    double sample_point_percent;
};

bool calculate_can_timing(uint32_t f_sys_hz, uint32_t target_baudrate, double target_sample_point, CAN_BitTimingConfig& config) {
    const uint32_t sync_seg = 1; // Fijo por norma ISO 11898
    
    for (uint32_t brp = 1; brp <= 1024; ++brp) {
        double t_q = static_cast<double>(brp) / static_cast<double>(f_sys_hz);
        double total_tq_double = 1.0 / (target_baudrate * t_q);
        uint32_t total_tq = static_cast<uint32_t>(std::round(total_tq_double));
        
        if (total_tq < 8 || total_tq > 25) continue; // Límites del controlador
        
        uint32_t phase_seg2 = static_cast<uint32_t>(total_tq * (1.0 - target_sample_point));
        if (phase_seg2 < 1) phase_seg2 = 1;
        
        uint32_t remaining = total_tq - sync_seg - phase_seg2;
        uint32_t prop_seg = remaining / 2;
        uint32_t phase_seg1 = remaining - prop_seg;
        
        if (prop_seg < 1 || phase_seg1 < 1) continue;
        
        config.brp = brp;
        config.prop_seg = prop_seg;
        config.phase_seg1 = phase_seg1;
        config.phase_seg2 = phase_seg2;
        config.sjw = phase_seg2; // SJW comúnmente igual a Phase_Seg2
        config.actual_baudrate = static_cast<double>(f_sys_hz) / (brp * total_tq);
        config.sample_point_percent = static_cast<double>(sync_seg + prop_seg + phase_seg1) / total_tq * 100.0;
        
        return true;
    }
    return false;
}

int main() {
    uint32_t f_sys = 80000000; // Clock de 80 MHz (ejemplo: MCU STM32 / ESP32-S3)
    uint32_t nominal_baud = 500000; // 500 kbps (Arbitraje)
    double sample_pt = 0.80; // 80% Punto de muestreo
    
    CAN_BitTimingConfig config;
    if (calculate_can_timing(f_sys, nominal_baud, sample_pt, config)) {
        std::cout << "--- Configuración de Bit Timing CAN Nominal ---\n";
        std::cout << "BRP: " << config.brp << "\n";
        std::cout << "Prop_Seg: " << config.prop_seg << " Tq\n";
        std::cout << "Phase_Seg1: " << config.phase_seg1 << " Tq\n";
        std::cout << "Phase_Seg2: " << config.phase_seg2 << " Tq\n";
        std::cout << "SJW: " << config.sjw << " Tq\n";
        std::cout << "Baudrate Real: " << config.actual_baudrate << " Hz\n";
        std::cout << "Sample Point: " << config.sample_point_percent << " %\n";
    } else {
        std::cout << "Error al calcular parámetros de timing.\n";
    }
    return 0;
}

Conclusiones para la Práctica en Ingeniería Mecatrónica

El correcto entendimiento de los niveles de tensión diferenciales y del cálculo estricto del bit timing previene fallas intermitentes en buses industriales causadas por réflex de línea o desincronización de relojes entre nodos. Al diseñar nodos CAN/CAN-FD, el ingeniero mecatrónico debe prestar especial atención a la impedancia adaptada de la red, la calibración precisa del punto de muestreo y la latencia del transceptor físico.