Concepts

Informative

The model behind the CAN driver: its two-level state machine, timing model, and event handling. Non-binding; the normative rules live in Can — Requirements.

State machine

The driver has a driver-wide state and, independently, a per-channel state.

Driver state

        stateDiagram-v2
   [*] --> CAN_DRV_STATE_UNINIT : Reset
   CAN_DRV_STATE_UNINIT --> CAN_DRV_STATE_INIT : Can_Init()
   CAN_DRV_STATE_INIT --> CAN_DRV_STATE_UNINIT : Can_DeInit()
    

Driver state

Meaning

API calls accepted

CAN_DRV_STATE_UNINIT

Not yet initialized (state after reset/startup)

Only Can_Init()

CAN_DRV_STATE_INIT

Initialized; service APIs are accepted

All

Channel state

After Can_Init, every channel starts in STOPPED. The upper layer drives transitions with Can_SetChannelState; hardware events (bus-off) can force a channel back to STOPPED.

All upper-layer channel transitions go through the single Can_SetChannelState API; the argument is the requested target state. The three operational states are grouped below as InitializedCan_Init enters the group and Can_DeInit leaves it from any of them.

        stateDiagram-v2
   direction LR

   [*] --> CAN_CH_STATE_UNINIT : Reset

   state "Initialized" as INIT {
      direction TB
      [*] --> CAN_CH_STATE_STOPPED
      CAN_CH_STATE_STOPPED --> CAN_CH_STATE_STARTED : SetChannelState(STARTED)
      CAN_CH_STATE_STARTED --> CAN_CH_STATE_STOPPED : SetChannelState(STOPPED)<br/>bus-off / unrecoverable error
      CAN_CH_STATE_STOPPED --> CAN_CH_STATE_SLEEP : SetChannelState(SLEEP)
      CAN_CH_STATE_SLEEP --> CAN_CH_STATE_STOPPED : SetChannelState(STOPPED)
   }

   CAN_CH_STATE_UNINIT --> INIT : Can_Init()
   INIT --> CAN_CH_STATE_UNINIT : Can_DeInit()
    

Channel state

Meaning

Valid transitions requested via

CAN_CH_STATE_UNINIT

Hardware not configured

Can_Init()STOPPED

CAN_CH_STATE_STOPPED

Initialized, not participating on the bus

STARTED, SLEEP, or Can_DeInit()

CAN_CH_STATE_STARTED

Actively participating; TX/RX enabled

STOPPED (also entered automatically on bus-off)

CAN_CH_STATE_SLEEP

Logical sleep (no wakeup detection)

STOPPED, or Can_DeInit()

Note

A requested transition may not take effect immediately if the hardware needs status-register polling to confirm it. In that case Can_SetChannelState does not block; completion is detected later by Can_CyclicFunction and reported via CanIf_OnChannelState. See Can — Requirements (CHI-CAN-MUST-03).

State transition sequence

The sequence below shows the two-step transition model: Can_SetChannelState requests a change, and — when the hardware cannot confirm it synchronously — Can_CyclicFunction later observes completion and reports it via CanIf_OnChannelState. This is the informative view of CHI-CAN-MUST-03.

        sequenceDiagram
   participant A as UpperLayer
   participant B as CanDrv
   participant C as CAN HW

   Note over A,C: Init time

   A->>B: Can_Init(&CanConfig)
   activate B
   B->>C: Initialize the hardware
   B-->>A: return
   deactivate B

   Note over A,C: Channel state change via Can_SetChannelState()

   A->>B: Can_SetChannelState(channelId, channelState)
   activate A
   activate B
   alt a development error is detected
      B-->>A: E_NOT_OK
   else
      B->>C: Set up HW registers / message objects
      opt HW transitions without delay
         B->>A: CanIf_OnChannelState(channel, channelState)
         activate A
         A-->>B: return
         deactivate A
      end
      B-->>A: E_OK
   end
   deactivate A
   deactivate B

   alt transition not yet complete in Can_SetChannelState()
      A->>B: Can_CyclicFunction()
      activate A
      activate B
      B->>C: Get HW status
      C-->>B: HW status
      opt HW has reached the requested state
         B->>A: CanIf_OnChannelState(channel, channelState)
         activate A
         A-->>B: return
         deactivate A
      end
      B-->>A: return
      deactivate A
      deactivate B
   end
    

Mailboxes and hardware objects

CAN hardware exposes a set of message objects, each holding an ID, a DLC, and the SDU data. The driver groups these into mailboxes: a mailbox is backed by one or more hardware object handles (HOHs), and both TX and RX mailboxes are configurable (CHI-CAN-MUST-17). How many hardware objects a mailbox uses determines its behavior:

Mailbox

Hardware objects

Meaning

RX

one

A single message object receives into the mailbox.

RX

several (same setup)

A hardware FIFO or several identically-configured objects (shadow buffer) back one RX mailbox, so a burst of frames is not lost (CHI-CAN-MUST-16).

TX

one

A single message object transmits the mailbox’s frames.

TX

several

Multiple hardware objects assigned to one TX mailbox for multiplexed transmission — an optional feature (CHI-CAN-MAY-01).

Not every hardware object has to be assigned; unused objects simply carry no mailbox.

Timing model: two scheduling functions

Polling-mode work is split across two functions by their timing needs:

Function

Typical period

Handles (when configured for polling)

Can_PollFunction

sub-millisecond / high frequency

TX-completion and RX events — the fast data path

Can_CyclicFunction

≥ 1 ms

Bus-off, other unrecoverable errors, and channel state-transition completion

Either may be an empty function if the corresponding events are all handled by interrupt.

Event handling: interrupt or polling

For each channel, TX, RX, and bus-off/error handling is independently configured as either interrupt or polling:

  • InterruptCan_Init enables the corresponding interrupt; Can_Interrupt services it.

  • PollingCan_Init disables the interrupt; Can_PollFunction / Can_CyclicFunction service the event.

Either way, the same upper-layer callbacks are invoked (CanIf_OnReception, CanIf_OnTransmission, CanIf_OnError, CanIf_OnChannelState).

Event handling sequence

The sequence below traces a transmission request and the subsequent event handling for both modes. In interrupt mode, Can_Interrupt services the hardware event; in polling mode, the same handling is driven from Can_PollFunction / Can_CyclicFunction. Either path fans out into the TX-completion, RX, bus-off, and error branches and invokes the same upper-layer callbacks.

        sequenceDiagram
   participant INTEG as Integration code
   participant UPL as UpperLayer
   participant DRV as CanDrv
   participant HW as CAN HW

   Note over INTEG,HW: TX L-PDU

   UPL->>DRV: Can_Transmit(mailboxId, &pdu)
   activate DRV
   activate UPL
   alt a development error is detected
      DRV-->>UPL: E_NOT_OK
   else HW buffer for the mailbox is BUSY
      DRV-->>UPL: CAN_BUSY
   else HW buffer is available
      DRV->>HW: Set up HW registers / message objects
      DRV->>HW: Initiate transmission
      DRV-->>UPL: E_OK
   end
   deactivate DRV
   deactivate UPL

   Note over INTEG,HW: Event handling

   alt event handling mode = interrupt
      HW->>DRV: Can_Interrupt()
      activate DRV
      opt unrecoverable error other than bus-off
         DRV->>HW: Cancel pending messages
         DRV->>HW: Reset / disable channel if needed
         DRV->>INTEG: LogM_Report(..., CAN_RTERR_UNRECOVERABLE)
         activate INTEG
         INTEG-->>DRV: return
         deactivate INTEG
      end
      opt bus-off detection
         DRV->>HW: Cancel pending messages
         DRV->>HW: Reset / disable channel if needed
         DRV->>UPL: CanIf_OnError(channel, CAN_ERR_BUS_OFF)
         activate UPL
         UPL-->>DRV: return
         deactivate UPL
      end
      opt TX L-PDU completion
         DRV->>UPL: CanIf_OnTransmission(canTxPduId)
         activate UPL
         UPL-->>DRV: return
         deactivate UPL
      end
      opt lost L-PDU
         DRV->>INTEG: LogM_Report(..., CAN_RTERR_DATALOST)
         activate INTEG
         INTEG-->>DRV: return
         deactivate INTEG
      end
      opt RX L-PDU
         DRV->>HW: Interpret mailbox, extract L-PDU
         DRV->>UPL: CanIf_OnReception(messageInfo, &pdu)
         activate UPL
         UPL-->>DRV: return
         deactivate UPL
      end
      DRV-->>HW: return from interrupt
      deactivate DRV
   else event handling mode = polling
      UPL->>DRV: Can_PollFunction() / Can_CyclicFunction()
      activate UPL
      activate DRV
      DRV->>HW: Get HW status
      Note left of DRV: Same handling as interrupt mode
      DRV-->>UPL: return
      deactivate DRV
      deactivate UPL
   end
    

Wakeup and sleep

A typical CAN transceiver can detect bus wakeup, but the CanDrv deliberately omits wakeup detection. Consequently SLEEP is a logical state: the channel stops participating but the driver does not arm any wakeup source.

Key terms

For CAN glossary terms — CAN controller, CAN channel, Hardware Object Handle (HOH), Hardware Object, Receive/Transmit Mailbox, CAN L-PDU / L-SDU — see the glossary in the appendix.