Home Learning Paths ECU Lab Assessments Interview Preparation Pricing Log In Sign Up
Log In Sign Up
Diagnostics

UDS Diagnostics

Complete mastery of Unified Diagnostic Services (ISO 14229). From basic service requests to advanced security access, ECU programming, and production diagnostic workflows.

32 chapters
25.0 hrs reading
6 modules

Overview

UDS (Unified Diagnostic Services per ISO 14229) is the universal language for ECU diagnostics. Every modern vehicle uses UDS for workshop diagnosis, ECU programming, and production end-of-line testing.

This course covers every UDS service in depth - from basic DiagnosticSessionControl and ReadDataByIdentifier to advanced security access sequences, routine controls, and ECU programming. You'll work with real diagnostic request/response patterns.

By the end, you'll be capable of designing complete diagnostic specifications, implementing diagnostic server software, and creating diagnostic test sequences used in production and aftermarket.

Course Modules

1
UDS Fundamentals (ISO 14229)
5 chapters • 4.0 hrs reading
UDS Architecture & Service ModelFREE PREVIEW 45 min read
▸ UDS (ISO 14229-1) service model: client-server architecture - tester (client) sends service request PDU, ECU (server) responds with positive response (first byte = SID + 0x40) or negative response (NRC = 0x7F + SID + NRC code); 7 service groups: Diagnostic Session Control, ECU Reset, Communication Control, Data Transmission, Stored Data Transmission (DTCs), I/O Control, Routine Control, Upload/Download; service addressed by single-byte SID (Service Identifier, 0x10–0x39)
▸ Addressing modes in UDS: Physical (unicast, single ECU) - tester uses ECU-specific CAN TX ID (e.g., 0x7E0 for ECU ID 0, response on 0x7E8); Functional (broadcast, all ECUs) - CAN ID 0x7DF; Tester Present (0x3E 0x80) uses functional addressing to keep all ECUs in active session simultaneously; DoIP addressing: UDS_SOURCE_ADDRESS in DoIP routing activation maps to ECU_LOGICAL_ADDRESS (16-bit, OEM-assigned); OEM-specific physical addresses allocated in CDD (CANdela Studio) diagnostic description file
▸ AUTOSAR DCM (Diagnostic Communication Manager) architecture: DCM processes UDS requests from PduR (PDU Router) which receives from CanTp (CAN Transport Protocol, ISO 15765-2) or SoAd (Socket Adapter for DoIP); DCM contains: DsdLayer (service dispatcher routes SID to handler), DspLayer (service processing with DEM/NVM/App calls), DslLayer (session/security state management, timing supervision - P2ServerMax, P2*ServerMax); application SWC implements DcmDspData_ReadDataFnc() callback returning signal values for configured DIDs
▸ Timing parameters per UDS ISO 14229-1: P2Server_max = 50 ms (maximum response time for standard response, ECU may send NRC 0x78 "Response Pending" if needs more time); P2*Server_max = 5000 ms (extended response time after NRC 0x78 sent, maximum total time before final response); P3Client = 5000 ms (tester session timeout - if no request sent within 5 s in non-default session, ECU may drop to DefaultSession); configure in AUTOSAR DcmTimingParameters: DcmTimStrP2ServerMax=50ms, DcmTimStrP2StarServerMax=5000ms
Diagnostic Sessions & Session TransitionsFREE PREVIEW 40 min read
▸ DiagnosticSessionControl (SID 0x10) sub-functions: 0x01 DefaultSession (always available, no security access required, OBD mode 01 available, limited DID read), 0x02 ProgrammingSession (enables UDS flash download services - RequestDownload 0x34, TransferData 0x36, TransferExit 0x37; requires prior SecurityAccess), 0x03 ExtendedDiagnosticSession (enables calibration writes, I/O control, ECU reset, DTC clear; most development services); OEM-specific sessions: 0x40–0x5F range (e.g., 0x40 = Manufacturer-specific session for factory EOL)
▸ Session state machine in AUTOSAR DCM: DCM manages session state internally - DcmDslSessionType enum (DCM_DEFAULT_SESSION, DCM_PROGRAMMING_SESSION, DCM_EXTENDED_SESSION); on request 0x10 0x03: DCM calls BswM_Dcm_RequestExtendedDiagnosticSession notification → BswM may enable/disable communication control or DEM event reporting; session change triggers SchM_Enter/Exit for exclusive area protection; on session timeout (no TesterPresent received within P3 timeout): DCM auto-transitions to DefaultSession and notifies DEM to enable DTC detection again
▸ Session-dependent service availability: each DCM service configured with DcmDsdSidTabServiceConfig.DcmDsdSubServiceSessionMask - bitmask of allowed sessions; example: DID 0xF190 (VIN) readable in DefaultSession (mask 0x01), DID 0xF1A0 (security log) readable in ExtendedSession + SecurityAccess level 0x01 only; 0x2E WriteDataByIdentifier for calibration data: ExtendedSession + SecurityLevel 0x03 required; AUTOSAR DCM enforces these rules before dispatching to application callback - sends NRC 0x22 (conditionsNotCorrect) if session constraint violated
▸ Programming session preconditions: before entering ProgrammingSession most OEMs require: (a) vehicle speed = 0 km/h (read from SWC signal), (b) engine off (ignition state = OFF or ACC), (c) battery voltage 11.0–14.5 V (checked by Dcm_ApplicationConditionCheckFnc callback); if any precondition fails: DCM returns NRC 0x22; precondition checks implemented in DcmDspSessionRow.DcmDspSessionForBoot callback; after preconditions pass and session confirmed: ECU may enable NVM write access and disable watchdog refresh to allow extended flash time
Request/Response Patterns & NRC Handling 50 min read
▸ UDS request/response PDU format: Request = [SID, Sub-function/DID high byte, DID low byte, Data...]; Positive response = [SID+0x40, Sub-function echo, Data...]; Negative response = [0x7F, SID, NRC]; example ReadDataByIdentifier request for VIN: 22 F1 90 → positive response: 62 F1 90 57 30 4C 4A 43... (62=0x22+0x40, F190=DID, 57..=17-char VIN ASCII); request/response transmitted via ISO-TP (multi-frame for responses > 7 bytes on CAN)
▸ NRC (Negative Response Code) reference table: 0x10=generalReject, 0x11=serviceNotSupported (SID not in server), 0x12=subFunctionNotSupported, 0x13=incorrectMessageLengthOrInvalidFormat, 0x14=responseTooLong, 0x21=busyRepeatRequest (try again after delay), 0x22=conditionsNotCorrect (session/voltage/speed precondition), 0x24=requestSequenceError (service called out of order), 0x25=noResponseFromSubnet, 0x26=failurePreventsExecutionOfRequestedAction, 0x31=requestOutOfRange (DID not configured), 0x33=securityAccessDenied, 0x35=invalidKey (wrong seed-key answer), 0x36=exceededNumberOfAttempts (lockout), 0x37=requiredTimeDelayNotExpired (retry too soon after lockout)
▸ Suppress positive response bit (SPR): sub-function byte bit 7 set to 1 instructs server not to send positive response - used by TesterPresent 0x3E 0x80 to keep session alive without flooding CAN bus with responses; other services: DiagnosticSessionControl 0x10 0x81 (0x01 | 0x80) suppresses session confirmation response; WARNING: ECU still executes the service, just doesn't respond - don't use SPR on write operations during debugging as you lose confirmation; AUTOSAR DCM: DcmDslSubServiceHandleId with DcmDsdSubServiceUsed=TRUE enables SPR handling
▸ NRC 0x78 (requestCorrectlyReceivedResponsePending) pattern: ECU returns 0x7F SID 0x78 to reset P2Server timer while processing long operation; maximum 3 pending responses before final response (OEM-specific, typ 3×5000ms = 15s total); use case: EraseMemory routine (0x31 0x01 0xFF00) taking 3.5s to erase 2MB flash - ECU sends 0x7F 0x31 0x78 every 4.9s to prevent tester timeout; AUTOSAR DCM: Dcm_DspEraseData callback returns DCM_E_PENDING → DCM automatically sends NRC 0x78 and polls callback again on next DCM main function cycle (typ. 10ms); callback must return DCM_E_OK when operation complete
Transport Layer - ISO 15765 (CAN) & DoIP 45 min read
▸ ISO 15765-2 (ISO-TP) frame types for CAN: Single Frame (SF) - PCI byte 0 = 0x0N (N=data length 1–7), max 7 bytes payload, no flow control needed; First Frame (FF) - PCI bytes 0-1 = 0x1NNN (NNN=total length up to 4095 bytes), data bytes 2-7, triggers FC response; Consecutive Frame (CF) - PCI byte 0 = 0x2N (N=sequence number 0x0–0xF cycling), 7 bytes data; Flow Control (FC) - PCI byte 0 = 0x30+FS (FS: 0=ContinueToSend, 1=Wait, 2=Overflow), byte 1=BlockSize (0=send all remaining CFs without waiting), byte 2=STmin (minimum separation time between CFs)
▸ ISO-TP timing parameters: N_Bs = max time for receiver to send FC after FF (typ. 1000 ms); N_Cr = max time for sender to wait for next CF after previous CF (typ. 1000 ms); N_Cs = actual CF separation time implemented by sender (≥ STmin value in FC); STmin values: 0x00=0ms, 0x01–0x7F = 1–127 ms, 0xF1–0xF9 = 100–900 µs (microsecond range); AUTOSAR CanTp configuration: CanTpNBs, CanTpNCr, CanTpNCs parameters; on N_Bs timeout: CanTp reports NRC 0x10 to DCM via PduR; CAN hardware extended addressing: adds 1 address byte before PCI for differentiated addressing
▸ DoIP (Diagnostics over IP, ISO 13400): L4 transport for UDS over automotive Ethernet; DoIP entity (vehicle gateway) listens on UDP port 13400 (vehicle discovery) and TCP port 13400 (diagnostic communication); tester performs UDP broadcast vehicle announcement → gateway responds with VIN + EID (6-byte Entity ID) + GID (6-byte Group ID); TCP connection established → RoutingActivation message (type 0x0005) activates routing for specific logical address; UDS PDUs encapsulated in DoIP generic UDP/TCP header (8 bytes: protocol version + inverse + payload type 2B + length 4B); AUTOSAR SoAd module manages DoIP sockets
▸ DoIP timing and NAD management: DoIP A_DoIP_General_Inactivity timeout = 5000 ms (TCP connection closed if no activity); A_DoIP_Alive_Check_Response = 500 ms (gateway sends alive-check if tester silent); gateway maintains routing activation table mapping tester source address to internal ECU logical addresses (OEM-assigned, e.g., 0x0010 = Engine ECU, 0x0020 = Gateway); multi-ECU access: tester activates routing for each target ECU separately; DoIP RoutingActivationType 0x00 = default activation (no authentication), 0x01 = OEM-specific (may require activation challenge handshake for security)
Hands-On: First UDS Communication 55 min read
▸ Hardware setup: connect Vector VN1610 CAN interface to ECU OBD-II port (CAN-H pin 6, CAN-L pin 14); open CANoe diagnostic console; configure network database (.dbc) and diagnostic description (.cdd) files; verify CAN communication at 500 kbit/s using CANalyzer measurement window - confirm periodic ECU CAN messages visible before attempting diagnostics
▸ Send first UDS request - DiagnosticSessionControl: in CANoe diagnostic console, select target ECU (CAN physical address 0x7E0); send 10 03 (ExtendedDiagnosticSession); observe response 50 03 00 19 01 F4 (50=positive, 03=ExtendedSession, 0019=P2ServerMax 25ms, 01F4=P2*ServerMax 500ms); if NRC 0x22 returned: check preconditions (vehicle speed, ignition state); send 3E 80 (TesterPresent suppress) every 2 seconds to keep session alive
▸ Read VIN: send 22 F1 90 → response 62 F1 90 [17 ASCII bytes]; decode ASCII: 57=W, 30=0, 4C=L, ... → confirm VIN matches vehicle label; Read ECU serial (DID 0xF18C): 22 F1 8C → 62 F1 8C [20-byte serial]; Read ECU software version (DID 0xF188): 22 F1 88 → 62 F1 88 [software version string]; using python-diagnostics (udsoncan library): client.read_data_by_identifier([0xF190, 0xF18C, 0xF188]) - reads multiple DIDs in single request, parses response automatically
▸ Read and clear DTCs: 19 02 08 (ReadDTCInformation subfunction 0x02 = ReportDTCByStatusMask, mask 0x08 = confirmed DTCs); response 59 02 [DTC list with status bytes]; if DTC P0100-12 stored: record freeze frame 19 04 P0 10 00 01 (subfunction 0x04 = ReportDTCSnapshotRecordByDTCNumber); clear all DTCs: 14 FF FF FF (ClearDiagnosticInformation, groupOfDTC = 0xFFFFFF = all); response 54 confirms clear; re-read DTCs to confirm cleared; document DTC codes, status bytes, and freeze frame data for engineering analysis
2
Data Services
6 chapters • 4.2 hrs reading
ReadDataByIdentifier (0x22) Deep Dive 45 min read
▸ Multi-DID read in single request: UDS allows multiple DIDs in one 0x22 request - 22 F1 90 F1 8C F1 88 reads VIN + serial + SW version; ECU responds with single PDU concatenating all DID data: 62 F1 90 [17 bytes VIN] F1 8C [20 bytes serial] F1 88 [SW version]; if any DID fails (not available): ECU returns NRC 0x31 (requestOutOfRange) and rejects entire request - OEMs often restrict multi-DID to same session level DIDs; maximum request length limited by CAN-TP buffer (typically 4095 bytes = max 2000+ DIDs in theory)
▸ AUTOSAR DCM DID configuration: each DID defined in DcmDspData container with DcmDspDataUsePort=USE_DATA_SENDER_RECEIVER or USE_DATA_ELEMENT_OF_PORT; DcmDspDid container links DID number (e.g., 0xF190), DcmDspDataByIdentifierRef (data content definition), DcmDspDidReadSessionRef (allowed sessions), DcmDspDidReadSecurityLevelRef (required security level); DcmDspData_ReadDataFnc() callback in application SWC fills buffer from Rte_IRead signal or NVM block; data length fixed (DcmDspDataSize in bits) or dynamic (DcmDspDataReadDataLengthFnc() callback returns actual length)
▸ Standardized DID assignments (ISO 14229-2, SAE J1979): 0xF190 = VIN (ISO 3779, 17 chars), 0xF18A = System Supplier ECU Hardware Number, 0xF18B = ECU Manufacturing Date (YYYYMMDD 4 bytes), 0xF18C = ECU Serial Number (max 20 chars), 0xF186 = Active Diagnostic Session (1 byte), 0xF187 = Vehicle Manufacturer Spare Part Number, 0xF188 = Vehicle Manufacturer ECU Software Number, 0xF180 = Boot Software Identification, 0xF181 = Application Software Identification, 0xF112 = System Supplier Identifier; 0x0000–0xEFFF = OEM-specific; 0xF000–0xF0FF = supplier-specific; 0xF100–0xF1FF = standardized
▸ Functional addressing and DID read across ECUs: tester sends 0x22 0xF1 0x90 on functional address 0x7DF → all CAN ECUs respond with their individual VINs on physical response addresses; used for fleet-wide DID read in production; AUTOSAR DCM: DcmDspDid.DcmDspDidFunctionalRequest=TRUE enables response to functional addressing; for DoIP network: each ECU receives broadcast and responds on its physical TCP stream; tester collects all responses by waiting for P3 timeout (5s) after sending functional request
WriteDataByIdentifier (0x2E) 35 min read
▸ WriteDataByIdentifier (SID 0x2E) use cases: write VIN at EOL (2E F1 90 [17-byte VIN ASCII]); write vehicle variant coding (2E F1 00 [variant bitmask]); write calibration parameters to NVM (2E D0 01 [idle_speed_target uint16]); write odometer for instrument cluster (2E F1 A0 [mileage 4 bytes little-endian]); response: 6E F1 90 (positive) or NRC 0x33 (securityAccessDenied if SecurityAccess not obtained first); NRC 0x78 if write triggers slow NVM flush (write to DFlash takes 50–200ms depending on sector size)
▸ AUTOSAR DCM write DID configuration: DcmDspDidWrite container with DcmDspDataWriteFnc callback = WriteData_DID_F190() in application SWC; callback parameters: (data buffer, data length, OpStatus, ErrorCode pointer); on first call OpStatus=DCM_INITIAL - start write, return DCM_E_PENDING if NVM write not complete; on subsequent calls OpStatus=DCM_PENDING - check NVM write status, return DCM_E_OK when done; DcmDspDidWriteSessionRef and DcmDspDidWriteSecurityLevelRef enforce access control; DataLength fixed (DcmDspDataFixedLength=TRUE) or validated via DcmDspDataConditionCheckReadFnc
▸ Write protection mechanisms: AUTOSAR NvM_WriteBlock() with NvM_SetBlockProtection() - once set TRUE, block reject further writes via DCM; OEM variant coding: write allowed only once at EOL (VehicleConfigurationLocked bit in NVM); ECU immobilizer data: written at production, locked with cryptographic write protection (SHE CMD_LOAD_KEY with write protection flag); attempt to write after lock returns NRC 0x26 (failurePreventsExecutionOfRequestedAction); security level required for 0x2E typically SecurityLevel 0x03 or 0x05 (OEM-defined)
▸ Validation and error handling in write callbacks: application callback must validate data before writing - check range (idle_speed between 600–900 RPM), check data pattern (VIN matches ISO 3779 charset: digits 0-9, uppercase A-Z except I/O/Q), check dependency (write trailer coupling variant only if tow-bar fitted signal = TRUE); on validation failure: set ErrorCode = DCM_E_REQUESTOUTOFRANGE → DCM returns NRC 0x31; on NVM write failure: ErrorCode = DCM_E_GENERALPROGRAMMINGFAILURE → NRC 0x72; always verify write success by re-reading DID after write in test sequence
DynamicallyDefineDataIdentifier (0x2C) 40 min read
▸ SID 0x2C sub-functions: 0x01 DefineByIdentifier - create dynamic DID from existing static DIDs: 2C 01 F3 00 F1 90 00 11 F1 8C 00 14 defines DDID 0xF300 as VIN[0..16] + SerialNo[0..19]; 0x02 DefineByMemoryAddress - create dynamic DID directly from RAM address: 2C 02 F3 01 14 0x20001234 04 reads 4 bytes from RAM address 0x20001234 (useful for direct variable access without DID wrapper); 0x03 ClearDynamicallyDefinedDataIdentifier - 2C 03 F3 00 removes DDID 0xF300 from server memory
▸ DDID configuration and memory: server maintains dynamic DID definition table in RAM (not NVM - lost after reset); table size configured in AUTOSAR DCM: DcmDspDDDIDMaxDynamicDIDNumber (typ. 4–16 dynamic DIDs), DcmDspDDDIDMaxDIDbyIdentifier (max source DIDs per dynamic DID, typ. 8); 0x2C 0x01 can reference only DIDs flagged with DcmDspDid.DcmDspDidDynamicRef=TRUE in configuration - prevents dynamic access to restricted DIDs; after defining DDID: read it with standard 0x22 request; delete all DDIDs on ECU reset or session change to default
▸ 0x2C 0x02 security implications: DefineByMemoryAddress allows reading arbitrary ECU RAM - powerful diagnostic tool but significant security risk; restrict to SecurityLevel 0x03 (engineering-only) via DcmDspDddiDescriptor.DcmDspDDDIDRequestedDIDRef security mask; OEM production ECUs should disable 0x2C 0x02 entirely (DcmDspDddiDescriptor = not configured); for development ECUs: allows reading any variable address without CDD update - accelerates debug cycle significantly; address validation: DCM checks address against DcmDspMemoryIdInfo address ranges to prevent reading HSM/SHE key memory regions
▸ Practical use case - dynamic diagnostic monitoring: during dynamic diagnosis session, engineer defines DDID 0xF301 = [engine_speed_rpm UINT16] + [injection_quantity_mg UINT16] + [lambda_current FLOAT32]; reads DDID at 100ms interval via CANoe test script loop; logs values to CSV; adjusts calibration map based on live data - all without changing CDD or recompiling DCM configuration; after session: clear DDID 0xF301; AUTOSAR DCM handles DDID reads identically to static DIDs - DDID response concatenates source DID data in definition order
ReadMemoryByAddress (0x23) 35 min read
▸ ReadMemoryByAddress (SID 0x23) request format: 23 [addressAndLengthFormatIdentifier 1 byte] [memoryAddress N bytes] [memorySize M bytes]; addressAndLengthFormatIdentifier byte: high nibble = M (bytes for memorySize), low nibble = N (bytes for memoryAddress); example reading 256 bytes from 0x20001000: 23 14 20 00 10 00 00 01 00 (N=4, M=1, address=0x20001000, size=256); response: 63 [256 bytes of data]; access controlled by DcmDspMemoryIdInfo address ranges and security level in AUTOSAR DCM
▸ AUTOSAR DCM memory access configuration: DcmDspMemoryIdInfo defines allowed memory regions per security level; DcmDspMemoryRangeInfo: DcmDspMemoryRangeHigh=0x70FFFFFF, DcmDspMemoryRangeLow=0x70000000 (Core0 DSPR), DcmDspMemoryRangeReadSecurityLevelRef → SecurityLevel 0x03; DcmDspMemoryRangeWriteSecurityLevelRef → SecurityLevel 0x05; memory regions not in DcmDspMemoryIdInfo: ECU returns NRC 0x31 (requestOutOfRange); critical exclusions: HSM key memory (0xF0000000+), OTP registers, and production-locked NVM blocks should never appear in readable ranges
▸ WriteMemoryByAddress (SID 0x3D): write arbitrary RAM: 3D [format] [address] [size] [data]; use case: inject fault condition for testing - write 0xFF to g_brake_pressure_sensor_fail flag to simulate sensor failure without hardware fault injection; write calibration override to RAM CHARACTERISTIC mirror address (use with caution - bypasses application validation); AUTOSAR DCM: DcmDspMemoryRangeWriteSecurityLevelRef must allow write; RAM write immediate (no NVM persistence); flash write via 0x3D: only if flash driver mapped in DCM memory range AND in ProgrammingSession + SecurityAccess level 0x05
▸ Bulk memory read for firmware extraction (security concern): 0x23 with large address range and repeated requests can read complete flash content - firmware reverse engineering risk; countermeasures: (a) restrict 0x23 to engineering SecurityLevel (not workshop level) via DcmDspMemoryRangeReadSecurityLevelRef; (b) flash addresses NOT included in allowed memory ranges (DcmDspMemoryIdInfo covers only RAM and DFlash diagnostic data regions); (c) for ASIL-D ECUs: disable 0x23 entirely in production firmware (remove DcmDspMemoryIdInfo entries in production configuration); verify restriction via CDD configuration review in DaVinci Configurator
InputOutputControlByIdentifier (0x2F) 45 min read
▸ SID 0x2F sub-functions (controlOptionRecord): 0x00 returnControlToECU - ECU resumes normal control of output; 0x01 resetToDefault - ECU resets output to default/safe value; 0x02 freezeCurrentState - ECU holds output at current value; 0x03 shortTermAdjustment - tester provides specific value: 2F D1 00 03 0B B8 controls DID 0xD100 (fuel injector pulse width) with value 0x0BB8 (3000µs); request includes enable mask byte specifying which parameter is being controlled; response: 6F D1 00 [statusRecord] confirms control accepted
▸ AUTOSAR DCM I/O control configuration: DcmDspDidControl container under DcmDspDid; DcmDspDidControlEnableMask - bitmask indicating which control options (returnControlToECU, resetToDefault, freezeCurrentState, shortTermAdjustment) are supported; DcmDspData_Control_FnctRef → application callback Ctrl_DID_D100() receives action enum and value; callback sets override flag in SWC: g_injector_pulse_override = value; application reads override flag: if(g_injector_pulse_override_active) use_override_value else use_calculated_value; AUTOSAR SchM exclusive area prevents race condition on override flag
▸ Safety constraints and watchdog for I/O override: ISO 26262 requirement: I/O override must automatically expire to prevent dangerous stuck state; implement timeout watchdog: DCM calls application callback with controlEnableState at each DCM MainFunction cycle (10ms); if controlEnableState = DCM_CONTROL_ACTIVE, application resets 5-second countdown timer; if timer expires without DCM refresh (e.g., tester disconnects), application calls returnControlToECU automatically; document override timeout in FMEA - "Tester disconnects while fuel injector controlled" → Watchdog: 5s, Effect: injector returns to calculated value
▸ Production use cases and restrictions: EOL functional tests: 2F D2 00 03 01 activates fuel pump relay (DID 0xD200, shortTermAdjustment=ON) → verify fuel pressure sensor reads expected value; headlamp alignment test: activate headlamp actuator via 0x2F, measure optical alignment on test stand; workshop: 2F C8 00 03 [RPM] controls idle speed for A/C compressor load test; production ECUs should restrict 0x2F to ExtendedSession + SecurityLevel 0x03 minimum; safety-critical outputs (ABS actuators, airbag squibs) should be completely excluded from 0x2F scope (DID not configured) to prevent misuse
Hands-On: Complete Data Service Implementation 60 min read
▸ DaVinci Configurator setup: in DCM module, create DcmDspDid container for DID 0xD100 (engine_torque_request UINT16); add DcmDspData: DcmDspDataSize=16bits, DcmDspDataReadFnc=ReadData_DID_D100, DcmDspDataWriteFnc=WriteData_DID_D100; link to DcmDspDidReadSessionRef=[DefaultSession, ExtendedSession], DcmDspDidWriteSessionRef=[ExtendedSession], DcmDspDidWriteSecurityLevelRef=[SecurityLevel_0x03]; generate code; AUTOSAR RTE creates Rte_IRead_ReadData_DID_D100() interface connecting DCM callback to application SWC port
▸ Application SWC callback implementation: Std_ReturnType ReadData_DID_D100(uint8* data, Dcm_OpStatusType opStatus, uint16* dataLength, Dcm_NegativeResponseCodeType* errorCode) { uint16 torque; Rte_Read_PP_EngineTorqueRequest_Value(&torque); data[0] = (uint8)(torque >> 8); data[1] = (uint8)(torque); *dataLength = 2; return DCM_E_OK; }; for write: Std_ReturnType WriteData_DID_D100(uint8* data, uint16 dataLength, Dcm_OpStatusType opStatus, Dcm_NegativeResponseCodeType* errorCode) { uint16 val = ((uint16)data[0] << 8) | data[1]; if(val > 5000) { *errorCode = DCM_E_REQUESTOUTOFRANGE; return DCM_E_NOT_OK; } Rte_IWrite_WriteDID_D100_Value(val); return DCM_E_OK; }
▸ CDD authoring in CANdela Studio: create Service_ReadDataByIdentifier → add DID 0xD100 "EngineTorqueRequest"; configure Data element: type UINT16, scale 0.1 Nm/bit, offset 0, unit "Nm"; add to DefaultSession and ExtendedSession; configure access rights (No SecurityAccess for read); export .cdd file; load in CANoe diagnostic console → DID visible in data element tree; add to test script: TestWaitForDiagResponse(TestSendDiag({0x22, 0xD1, 0x00}), 500ms, "Read Engine Torque")
▸ CAPL test script for data service validation: testcase ReadWriteDID_D100() { diag tester on; long rc; diag req rd = new DiagRequest("ReadDataByIdentifier::EngTorqueRequest"); rd.SendRequest(); rc = rd.WaitForResponse(500); testResult(rc==0, "Read DID 0xD100 positive response received"); float torque = rd.GetLastResponse().GetParameter("EngineTorqueRequest"); testResult(torque >= 0 && torque <= 500, "Value in valid range"); DiagRequest wr = new DiagRequest("WriteDataByIdentifier::EngTorqueRequest"); wr.SetParameter("EngineTorqueRequest", 250.0); wr.SendRequest(); rc = wr.WaitForResponse(500); testResult(rc==0, "Write DID 0xD100 succeeded"); }; run in CANoe test environment and verify pass/fail
3
DTC Management
6 chapters • 4.8 hrs reading
DTC Storage Concepts & Status Byte 50 min read
▸ UDS DTC status byte structure (ISO 14229-1 §B.1): 8 bits - bit 0: testFailed (TF, current failure), bit 1: testFailedThisOperationCycle (TFTOC), bit 2: pendingDTC (failure in any previous or current cycle), bit 3: confirmedDTC (failure confirmed via debounce threshold), bit 4: testNotCompletedSinceLastClear (TNCTSLC), bit 5: testFailedSinceLastClear (TFSLC), bit 6: testNotCompletedThisOperationCycle (TNCTOC), bit 7: warningIndicatorRequested (MIL lamp control); typical workshop read mask: 0x09 (bits 0+3 = testFailed OR confirmedDTC)
▸ AUTOSAR DEM DTC event lifecycle: Dem_ReportErrorStatus(eventId, DEM_EVENT_STATUS_PREFAILED) - signal pre-failure; DEM applies debounce counter: DemDebounceCounterBasedClass IncrStepSize=1, DecrStepSize=1, FailedThreshold=10, PassedThreshold=-5; after 10 consecutive failures: status bit 0+2+3 set, DEM allocates primary memory slot and stores snapshot data; OEBD debounce via DemDebounceMonitorInternal: application calls Dem_SetEventStatus(PREFAILED/PRETESTED) from monitor runnable, DEM handles counter internally; healing: after PassedThreshold reached, bit 0 cleared, bit 3 remains (confirmedDTC persists)
▸ DTC storage and memory management: AUTOSAR DEM primary memory (DemPrimaryMemory): stores confirmed DTCs with snapshot data and extended data; capacity configurable (DemMaxNumberEventEntryPrimary typ. 20–40 DTCs); displacement policy: DemDTCDisplacementStrategy - OLDEST (displace oldest DTC when memory full), LATEST (displace newest), NONE (reject new DTC if full, returns DEM_E_NO_DTC_AVAILABLE); DEM secondary memory (DemMirrorMemory): optional separate NVM area for long-term historical DTCs; permanent memory (DemPermanentMemory): for OBD - DTCs remain after ClearDiagnosticInformation until OBD readiness confirmed
▸ OBD DTC format vs UDS DTC format: OBD SAE J2012 format: 5-character format P0100 where P/B/C/U = system (Powertrain/Body/Chassis/Network), first digit = OBD category, remaining 4 digits = fault code; UDS 3-byte format: byte 1-2 = ISO 14229 DTC number (0x000000–0xFFFF00 OEM range), byte 3 = DTC failure type (0x01=threshold exceeded, 0x02=circuit open, 0x03=circuit short to ground); AUTOSAR DEM maps J2012 format to ISO format: P0100 = 0x010100; UDS ReadDTCInformation returns ISO format; Mode 03 (OBD DTC read via SAE J1979) returns J2012 format; DEM maps between formats via DemDTCClass.DemObdDTC
ReadDTCInformation (0x19) - All Sub-Functions 55 min read
▸ 0x19 sub-function map: 0x01 reportNumberOfDTCByStatusMask (returns 2-byte count), 0x02 reportDTCByStatusMask (returns list: 3-byte DTC + 1-byte status byte per entry), 0x04 reportDTCSnapshotRecordByDTCNumber (DTC + snapshotRecordNumber 0xFF = all records), 0x06 reportDTCExtDataRecordByDTCNumber (DTC + extDataRecordNumber), 0x09 reportDTCWithSeverityInformation (adds 1-byte DEM severity + functional unit), 0x0A reportSupportedDTCs (all supported regardless of status), 0x14 reportDTCFaultDetectionCounter (returns faultDetectionCounter per DTC), 0x15 reportDTCWithPermanentStatus (OBD permanent fault codes not clearable by 0x14)
▸ AUTOSAR DCM routing: Dcm receives 0x19 request → DsdLayer selects DcmDspDtc service handler → DspLayer calls DEM API; for sub-function 0x02: Dem_SetDTCFilter(DTCStatusMask, DEM_DTC_KIND_ALL_DTCS, DEM_DTC_FORMAT_UDS, DEM_DTC_ORIGIN_PRIMARY_MEMORY, DEM_FILTER_WITH_SEVERITY_NO, 0, DEM_FILTER_FOR_FDC_NO) → then Dem_GetNextFilteredDTC(&dtc, &dtcStatus) loop until Dem_GetNextFilteredDTC returns DEM_NO_SUCH_ELEMENT; DEM builds response buffer with each DTC group (highByte, middleByte, lowByte, statusByte)
▸ DTC status byte interpretation in 0x19 response: bit0=testFailed (TF), bit1=testFailedThisOperationCycle (TFTOC), bit2=pendingDTC, bit3=confirmedDTC, bit4=testNotCompletedSinceLastClear (TNCTSLC), bit5=testFailedSinceLastClear (TFSLC), bit6=testNotCompletedThisOperationCycle (TNCTOMC), bit7=warningIndicatorRequested (WIR); statusMask in 0x02 request acts as filter - ECU ANDs statusMask with stored statusByte for each DTC; common tester call: 19 02 08 → returns all confirmed DTCs (bit3 set)
▸ CANoe Diagnostic Console usage: open Diagnostic → UDS → ReadDTCInformation; configure statusMask filter in request window; inspect response DTC list with decoded status bits; for snapshot access send 19 04 [DTC-high] [DTC-mid] [DTC-low] FF - response contains snapshotRecordNumber + DID list with values at time of fault; use python-udsoncan: client.get_dtc_by_status_mask(0x08) returns list of Dtc objects with .id and .status.confirmed_dtc boolean
ClearDiagnosticInformation (0x14) 35 min read
▸ 0x14 service structure: SID 0x14 + 3-byte groupOfDTC parameter; standardized group values: 0xFFFFFF = all DTCs, 0x000000 = emission-related OBD DTCs, 0xF4xxxx–0xF6xxxx = OBD group ranges; ECU-specific group IDs defined in CDD; positive response: 0x54 (no additional data); NRC matrix: 0x31 requestOutOfRange (groupOfDTC not supported), 0x22 conditionsNotCorrect (ECU in wrong mode - e.g., engine running), 0x24 requestSequenceError (programming session precondition), 0x72 generalProgrammingFailure (NvM write failure)
▸ AUTOSAR DCM → DEM call chain: DCM receives 0x14 → calls Dem_ClearDTC(groupOfDTC, DEM_DTC_KIND_ALL_DTCS, DEM_DTC_ORIGIN_PRIMARY_MEMORY); DEM clears all matching event entries: resets status byte to 0x50 (TNCTSLC + TNCTOMC), removes snapshot/extended data records from primary memory, resets FaultDetectionCounter, marks all-pass for debounce; if DEM needs NvM write time, returns DEM_CLEAR_PENDING → DCM sends NRC 0x78 response-pending, retries Dem_ClearDTC until DEM_CLEAR_OK; OBD permanent DTCs (Dem_IndicatorType PERMANENT_FAULT) survive 0x14 - cleared only after warm-up cycle passes OBD monitors
▸ Preconditions in production ECUs: many OEMs restrict 0x14 to Extended Diagnostic Session (10 03) or require SecurityAccess level unlocked; AUTOSAR DcmDspService configuration: DcmDspServiceSessionModeRule references allowed sessions; some ECUs require specific key-off/key-on cycle (DEM warm-up counter reset) before confirmedDTC status bit clears; DTC mirror memory (DemMirrorMemory): separate NvM partition preserving snapshot before clear for warranty analysis
▸ Practical workflow: after 0x14, verify clear with 0x19 0x02 0xFF (all active status mask) - empty response means clear successful; use CANoe Diagnostic → ClearDTCGroup dialog; common error: tester sends 0x14 while ECU in default session → NRC 0x22; mitigation: always open extended session (10 03) before clearing; python-udsoncan: client.clear_dtc(0xFFFFFF) handles pending response automatically via P2*/S3 timing management
DTC Snapshot & Extended Data Records 45 min read
▸ Snapshot record architecture: DemSnapshotClass groups multiple DIDs captured at moment of DTC confirmation; AUTOSAR configuration: DemDTCClass → DemDtcGroup → DemEventParameter → DemDTCAttributesClass → DemSnapshotRecordClass (DemSnapshotRecordNumber 0x01–0xFE, DemDIDClass reference); each DemDIDClass lists DemDIDDataElementClass with DemDataElementReadFnc callback (SWC port call returns current signal value at capture time); multiple snapshot records per DTC supported (e.g., record 0x01 = first occurrence, record 0x02 = most recent)
▸ Extended data record architecture: DemExtendedDataRecordClass captures DEM-internal statistics rather than application signals; standard records: record 0x01 = occurrence counter (1 byte, increments each TFTOC transition), record 0x02 = agingCounter (decrements each passed operation cycle), record 0x10 = faultDetectionCounter (signed byte, -128=passed, +127=failed); AUTOSAR: DemDTCAttributesClass → DemExtendedDataClass → DemExtendedDataRecordClass (DemExtendedDataRecordNumber, DemExtendedDataRecordKind = DEM_EXTENDED_RECORD/DEM_EXTENDED_OBD_RECORD); OEM-specific records allowed for aging cycle count, cumulative failure time, or operating hours at failure
▸ 0x19 sub-function interactions: sub-function 0x04 reportDTCSnapshotRecordByDTCNumber - request: [19][04][DTC-high][DTC-mid][DTC-low][snapshotRecordNumber]; response includes: DTC (3B) + snapshotRecordNumber + snapshotRecordNumberOfIdentifiers + {DID (2B) + data} for each DID in record; sub-function 0x06 reportDTCExtDataRecordByDTCNumber - request: [19][06][DTC][extDataRecordNumber]; response: DTC + extDataRecordNumber + data bytes; extDataRecordNumber 0xFE = all OBD records, 0xFF = all records
▸ DEM memory sizing impact: each snapshot record consumes RAM/NvM proportional to sum of DID data sizes; DemMaxNumberEventEntryPrimary (e.g., 10 events) × snapshot size must fit in NvM block; DemNvRamBlockId assignment in AUTOSAR maps DEM event memory to NvM blocks (NvMBlockDescriptor); at ECU init: Dem_Init() → DEM reads NvM blocks via NvM_ReadAll to restore previous DTC/snapshot state; key tool: ODXStudio - define snapshot DID list in SDDB (Software Data Description Base) file linking DEM DID callbacks to CANoe environment variable signals for live capture visualization
Aging, Displacement & Priority 40 min read
▸ DEM aging mechanism: AUTOSAR DemAgingAllowed=TRUE per DemDTCAttributesClass; aging begins when confirmedDTC transitions to not-failed (TFTOC=0) and DemAgingCycleRef operation cycle passes; DemAgingCycleCounterThreshold (e.g., 40 cycles) defines how many consecutive passed cycles before DTC is aged out of memory; aging counter stored in extended data record (decrements each cycle); DEM_EVENT_STATUS_PASSED reported via Dem_ReportErrorStatus → TFTOC cleared → aging cycle counting begins; after threshold: confirmedDTC bit cleared, DTC removed from primary memory, status byte reset to 0x00 (fully healed)
▸ Displacement strategy: when primary memory full (DemMaxNumberEventEntryPrimary reached) and new DTC must be stored, DEM applies DemDTCPriorityOfEventEntry comparison; lower priority value = higher priority (DemDTCPriority: 1=highest, 255=lowest); DEM displaces lowest-priority non-confirmed DTC first; if all DTCs confirmed with equal priority, displacement inhibited - NRC 0x21 busy returned; DemMaxNumberEventEntryMirror = additional overflow storage (mirror memory) for warranty; AUTOSAR DemEventDisplacement: DEM_DISPLACEMENT_PRIO_OCC_BASED selects between priority and occurrence-count-based displacement
▸ OBD-specific aging (ISO 15031 / SAE J1979 Mode 01 PID 01 readiness): OBD pending DTC (bit2) set after single failed cycle; OBD confirmed DTC (bit3 + MIL request) set after 2 consecutive failed cycles; healing requires: 3 consecutive passed OBD drive cycles (warm-up cycles with monitor completion) → MIL off; permanent DTC (bit7 WIR) set for emission DTCs - not erasable by 0x14, clears only after OBD monitor passes 3 times with successful warm-up; DEM config: DemDTCKind=DEM_DTC_KIND_EMISSION_DTC enables OBD aging rules
▸ Priority design patterns: tier-1 safety events (e.g., airbag SRS faults) get DemDTCPriority=1; powertrain emission DTCs get priority=2; comfort/infotainment body DTCs get priority=3; snapshot data preserved at lower NvM cost for high-priority events by capturing fewer DIDs; AUTOSAR DemEventParameter → DemDTCClass → DemDTCAttributesClass → DemDTCPriority assignment; in practice: BMW FI (Functional Integration) testing validates displacement by simultaneously triggering 11 low-priority DTCs on 10-entry primary memory - verifies oldest non-confirmed DTC is displaced first
Hands-On: DTC Configuration & Testing 60 min read
▸ AUTOSAR DEM configuration exercise: define a new DTC 0x012345 for an overvoltage event; create DemEventParameter (DemEventId=0x0001, DemDTCRef→DemDTC (UDS DTC value=0x012345), DemOperationCycleRef→DemOperationCycle_PowerCycle); configure DemDebounceCounterBasedClass (DemDebounceCounterFailedThreshold=10, DemDebounceCounterPassedThreshold=-5, DemDebounceCounterIncrementStepSize=1, DemDebounceCounterDecrementStepSize=1); add DemSnapshotRecordClass with DID 0x0101 capturing battery voltage SWC port; configure DemExtendedDataClass with occurrence counter record 0x01; set DemDTCPriority=2, DemAgingCycleCounterThreshold=40
▸ Fault injection in CANoe: use system variable manipulation in CAPL to simulate 11 consecutive Dem_ReportErrorStatus(0x0001, DEM_EVENT_STATUS_FAILED) calls (triggering debounce counter to threshold) → verify DTC status byte = 0x2F (TF + TFTOC + pending + confirmed + TNCTSLC); then inject 5 passed calls to verify counter decrements; use CANoe DEM simulation panel → Event Trigger window to inject fault status; check Diagnostic Console 0x19 0x02 0x0F response for DTC 0x012345 with status byte 0x0F
▸ Snapshot verification workflow: after DTC confirmed, send 19 04 01 23 45 FF (all records); parse response: [59 04] [01 23 45] [01] [01] [01 01] [02 xx] - snapshotRecord=01, numberOfIdentifiers=01, DID=0x0101, data=02h (battery voltage 14.2V scaled); verify data matches signal value at time fault was confirmed; access extended data with 19 06 01 23 45 FF → response includes record 0x01 = occurrence counter (should be 0x01 for first confirmation); repeat injection 3 more times → counter becomes 0x04
▸ Aging and clear test sequence: open CANoe extended session (10 03), confirm DTC is stored (19 02 0F), simulate 5 passed operation cycles (DemAgingCycleRef trigger in CANoe via DEM_APPL_CONDITION_PASSED callback), check extended data record 0x02 aging counter decrements; clear DTC with 14 FF FF FF → verify 54 positive response → read 19 02 0F → empty response confirms clear; common pitfalls: forgetting to open extended session before 0x14 (NRC 0x22), DemDebounceCounterPassedThreshold not negative (preventing healing), DemAgingAllowed=FALSE preventing automatic removal
4
Security & Access Control
5 chapters • 3.8 hrs reading
SecurityAccess (0x27) - Seed & Key 50 min read
▸ 0x27 service sub-function numbering: odd values = requestSeed (0x01, 0x03, 0x05 for access levels 1, 2, 3), even values = sendKey (0x02, 0x04, 0x06 for corresponding levels); positive response to requestSeed: [67][subFunc][seedBytes...] - if already unlocked, ECU returns seed=0x00 (all zeros) to indicate no key required; security level mapping: level 0x01 typical for ExtendedDiagnosticSession read-write access, level 0x03 for programming session (flash), level 0x09/0x0B for production/EOL specific access; DcmDspSecurityRow configuration in AUTOSAR maps each level to callback functions
▸ Seed generation best practices: ECU generates 4-byte (or 8-byte OEM-specific) seed using hardware TRNG (True Random Number Generator) on Aurix TC3xx TRNG module or SHE CMD_RND; seed must be unique per power cycle - never static/predictable; AUTOSAR callback: Dcm_GetSeedFnc(securityAccessType, seedLen, seed) - SWC implements this via CsmJob referencing a PRNG or TRNG; NRC 0x22 conditionsNotCorrect returned if preconditions not met (wrong session, ECU not ready); NRC 0x24 requestSequenceError if sendKey received without prior requestSeed
▸ Key computation algorithms: classical approach: key = XOR(seed, masterKey) - insecure, avoid; production approach: key = AES-128-ECB-Encrypt(seed, secretKey) - key held in secure element or SHE slot; HMAC approach: key = HMAC-SHA256(seed, secretKey)[0:4] (truncated to 4 bytes); AUTOSAR CsmJob reference: CsmJob_SecurityAccess_Level1 → CryptoKeyRef → SheKeySlot_SA_L1 (SHE slot 4); tester side: key calculation DLL (Windows) or python-udsoncan SecurityAlgorithm subclass overriding processServerResponse(seed) → compute and return key bytes
▸ Failed attempt lockout: DcmDspSecurityRow DcmDspSecurityNumAttDelay=3 (max failed attempts), DcmDspSecurityDelayTime=10000ms (10s lockout period); after 3 consecutive wrong keys: NRC 0x36 exceededNumberOfAttempts + DCM starts DcmDspSecurityDelayTime timer; during lockout all 0x27 requests return NRC 0x37 requiredTimeDelayNotExpired; lockout counter stored in RAM (resets on power cycle) or NvM (survives reset) depending on DcmDspSecurityADPUnlockAttemptCounterEnabled; AUTOSAR Dcm_GetSecurityLevel() returns current unlocked level (0x00 = locked); at ECU init: security level always resets to 0x00
Authentication (0x29) - Certificate-Based 45 min read
▸ ISO 14229-1:2020 service 0x29 (Authentication) sub-function map: 0x00 deAuthenticate (revokes access, returns to securityLevel 0), 0x01 verifyCertificateUnidirectional (tester proves identity with X.509 cert), 0x02 verifyCertificateBidirectional (mutual - ECU also proves identity), 0x03 proofOfOwnership (sends signature over challenge), 0x04 transmitCertificate (delivers intermediate CA cert chain to ECU), 0x07 requestChallengeForAuthentication (ECU generates nonce for tester); four-step bidirectional flow: 29 07 → ECU nonce → tester signs nonce → 29 02 {cert, signature} → ECU verifies → 29 03 {proof} → ECU sends own signed challenge → tester verifies → access granted
▸ Certificate structure: X.509v3 DER-encoded; SubjectAltName = URI urn:autosar:diagnostic-tester:tool-id-XYZ; KeyUsage: digitalSignature; ECDSA P-256 or RSA-2048; ECU stores OEM Root CA public key in hardware (SHE key slot or Aurix eHSM); validation chain: tester cert → intermediate CA → OEM Root CA → verifies via PKI revocation check (OCSP or CRL pre-loaded at ECU); AUTOSAR CryptoStack: CsmJob_Auth029_CertVerify → CryptoPrimitiveAlgorithmFamily=ECDSA, CryptoPrimitiveAlgorithmMode=SHA256; positive response 0x69 contains communicationConfiguration byte indicating granted access level
▸ Comparison with 0x27 SecurityAccess: 0x27 = symmetric key-based (shared secret, simpler, used for legacy ECUs and production); 0x29 = asymmetric PKI-based (stronger, required for UNECE R155 CSMS compliance, mandatory for OTA and remote diagnostics); 0x27 vulnerable to key extraction from binaries; 0x29 private key never leaves HSM/SHE - only signature produced; AUTOSAR DcmDspAuthentication config: DcmDspAuthenticationClass → DcmDspAuthenticationRole table mapping certificate subject fields to diagnostic access roles (e.g., role=ENGINEER grants all services, role=READONLY grants 0x22 only)
▸ Integration with AUTOSAR CSM: CsmJob_Auth_CertParse → parse X.509 DER cert; CsmJob_Auth_SigVerify → ECDSA-P256 signature verification over challenge bytes; CsmJob_Auth_HashCalc → SHA-256 for nonce hashing; CsmKeyRef_OEM_RootCA → Crypto Key element holding OEM CA public key bytes (provisioned at EOL); DCM timer: DcmDspAuthenticationTimeout (e.g., 30s) - if bidirectional challenge not completed within timeout, session reverts; tester tool requirement: CANoe .NET API or python-udsoncan Authentication plugin generating ECDSA signatures using tester private key (PEM format) loaded from HSM or software key store
Secured Data Transmission 40 min read
▸ ISO 14229-1 service 0x84 SecuredDataTransmission: wraps any other UDS service in a security envelope; request structure: [84][securityDataRequestRecord] where securityDataRequestRecord = {securityParameterIdentifier (2B) + securedMessage}; securedMessage = encrypted/MAC-protected payload of the inner UDS service PDU; positive response: [C4][securityDataResponseRecord]; inner service executed after signature/MAC verification on DCM side; use cases: transmitting signed calibration data (0x2E writes with CMAC), verifying firmware chunk integrity during 0x36 TransferData, protecting ReadDataByIdentifier responses carrying sensitive production keys
▸ Security parameter identifier (SPI) structure: 2-byte field identifies algorithm suite and key index; OEM-defined SPI table example: 0x0001 = AES-128-CMAC integrity only, 0x0002 = AES-128-GCM (encrypt + authenticate), 0x0003 = ECDSA-P256 signature verification; AUTOSAR DCM: DcmDspSecuredDataTransmission → DcmDspSecuredDataTransmissionSpi entries map SPI values to CsmJob references; CsmJob_SDT_MacVerify uses symmetric session key (derived via HKDF from SecurityAccess seed-key exchange or 0x29 session key) stored in CsmKey slot; freshness counter embedded in securityDataRequestRecord to prevent replay attacks
▸ Calibration data protection workflow: engineering tool generates calibration data + computes AES-128-CMAC tag (16 bytes) using session key; wraps in 0x84 request: [84][SPI=0x0001][freshness-counter 4B][0x2E DID data CMAC]; ECU DCM receives 0x84 → passes to CsmJob_SDT_MacVerify → if MAC valid extracts inner [2E DID data] → routes to WDBI handler → returns inner 0x6E response wrapped in 0xC4; if MAC fails: NRC 0x35 invalidKey returned; replay protection: ECU rejects if freshness counter ≤ stored last-seen counter
▸ 0x84 vs transport-layer security comparison: 0x84 is application-layer security (service-level granularity, individual UDS PDUs); DoIP/TLS provides transport-layer security (whole channel); 0x84 can be used inside TLS for defense-in-depth or on legacy CAN networks where TLS is unavailable; key limitation: requires symmetric session key pre-established via SecurityAccess or Authentication; AUTOSAR implementation constraint: 0x84 handler in DCM must be stateless (session key provided per call via CsmKeyRef) - no persistent connection state at UDS application layer; tool support: CANoe DiagnosticConsole supports 0x84 framing via XML-based service template configuration
Security Levels & Access Rights 35 min read
▸ AUTOSAR DCM service availability matrix: DcmDspServiceIdList assigns each UDS service (SID) to one or more DcmDspSessionRow entries; DcmDspServiceSessionRef links service to allowed sessions (DefaultSession, ExtendedDiagnosticSession, ProgrammingSession); additionally DcmDspSecurityLevelRef restricts service to specific unlocked security levels; combined requirement: current session AND security level must both satisfy service's configuration; example: 0x2E (WDBI) may be allowed in ExtendedSession AND require SecurityLevel 0x01 unlocked - tester must first 0x10 03 then 0x27 01/02 before any 0x2E write
▸ Per-DID and per-DTC security masks: DcmDspData → DcmDspDataUsePort → R-port to SWC; DcmDspDataConditionCheckReadFnc callback checks security level before data retrieval; DcmDspDataReadSecurityLevelRef maps individual DID read to required security level; similarly DcmDspDataWriteSecurityLevelRef for writes; OBD PIDs (0xF4xx range) available in DefaultSession without security; VIN DID 0xF190 readable without security, ECU hardware number 0xF18A writable only under security; DcmDspDTCSettingGroup restricts DTC enable/disable (0x85) to specific security levels
▸ Multi-level access architecture example for a powertrain ECU: SecurityLevel 0x00 (no unlock required) - read DID, read DTC (0x19), communication check (0x3E); SecurityLevel 0x01 (ExtendedSession key) - write calibration DIDs (0x2E), control actuators (0x2F), enable/disable DTC (0x85); SecurityLevel 0x03 (ProgrammingSession key, stricter algorithm) - 0x34/0x36/0x37 flash download, 0x31 erase routine; SecurityLevel 0x09 (EOL key, production-only) - write permanent variant coding, EOL lock flag; each level requires separate 0x27 seed-key exchange with distinct algorithm/key material
▸ Session/security state machine enforcement: on session timeout (S3Server expiry) ECU reverts to DefaultSession and SecurityLevel 0x00; on ECUReset (0x11) security level always resets; on session change (0x10) security level resets to 0x00 - tester must re-authenticate in new session; AUTOSAR DcmDspSecurityRow: DcmDspSecurityADPAuthenticationMaxNumberAttempts (5) → after exceeded: DcmDspSecurityADPDelay (600s = 10min lockout) prevents brute-force; OEM-specific: some suppliers use sticky security levels across DefaultSession (non-standard, discouraged); audit requirement: all security level transitions logged to AUTOSAR IdsM intrusion detection for CSMS compliance
Hands-On: Security Access Implementation 55 min read
▸ AUTOSAR DCM configuration exercise: add SecurityLevel 0x01 to an existing ECU project; in DcmDspSecurityRow add entry: DcmDspSecurityAccessType=0x01, DcmDspSecuritySeedSize=4, DcmDspSecurityKeySize=4, DcmDspSecurityNumAttDelay=3, DcmDspSecurityDelayTime=10000, DcmDspSecurityGetSeedFnc=App_GetSecuritySeed_L1, DcmDspSecurityCompareKeyFnc=App_CompareKey_L1; implement App_GetSecuritySeed_L1: call CsmRandomGenerate → store 4-byte seed in static RAM → return E_OK; implement App_CompareKey_L1: compute AES-128-ECB-Encrypt(storedSeed, masterKey) → compare with received key → return E_OK or E_NOT_OK
▸ CANoe CAPL security access script: on key F5 trigger: DiagSendRequest("27 01"); on response 0x67 0x01 parse bytes 3-6 as seed[0-3]; compute key = XOR(seed[0-3], {0xAA, 0xBB, 0xCC, 0xDD}) (simplified demo algorithm); DiagSendRequest("27 02 " + HexStr(key)); on response 0x67 0x02: write("Security Access Level 1 GRANTED"); on NRC response: write("Security Access FAILED, NRC=" + NRC); observe timing: requestSeed to positive response typically <50ms on CAN; if NRC 0x37 (delay required) wait 10s and retry
▸ Lockout behavior testing: script: loop 4 times sending 27 02 with deliberately wrong key [00 00 00 00]; verify first 3 attempts return NRC 0x35 (invalidKey); 4th attempt returns NRC 0x36 (exceededNumberOfAttempts); subsequent attempts immediately return NRC 0x37 (requiredTimeDelayNotExpired); wait DcmDspSecurityDelayTime (10s) → retry → NRC 0x35 again (new attempt allowed); validate: power cycle during lockout - verify lockout resets (RAM-based counter) vs survives (NvM-based); check AUTOSAR DcmDspSecurityADPUnlockAttemptCounterEnabled=TRUE for NvM persistence
▸ python-udsoncan complete security access flow: conn = IsoTPSocketConnection('vcan0', rxid=0x7E8, txid=0x7E0); client = Client(conn, request_timeout=2); client.change_session(DiagnosticSessionControl.Session.extendedDiagnosticSession); client.unlock_security_access(0x01, security_algo_callback); where security_algo_callback(seed, params): key = bytes([s^k for s, k in zip(seed, MASTER_KEY)]); return key; verify: client.read_data_by_identifier([0xF190]) succeeds (requires security unlock); common pitfalls: not switching to extended session before 0x27, static seed (PRNG not seeded), key algorithm mismatch between ECU and tester DLL
5
ECU Programming & Updates
5 chapters • 4.2 hrs reading
Reprogramming Sequence Overview 45 min read
▸ ISO 14229-1 compliant ECU reprogramming sequence (11 steps): 1) Open ExtendedDiagnosticSession [10 03]; 2) SecurityAccess Level 3 request seed [27 05] + compute key + send key [27 06]; 3) Check programming preconditions [31 01 FF 01] - ECU validates engine-off, voltage OK, gear-park; 4) Switch to ProgrammingSession [10 02]; 5) SecurityAccess Level 1 for programming [27 01]/[27 02]; 6) Erase flash memory [31 01 FF 00 + address/size]; 7) RequestDownload [34 00 44 memAddress memSize]; 8) TransferData loop [36 blockCounter data...] repeated; 9) TransferExit [37]; 10) Check programming integrity [31 01 02 02 + expected-CRC]; 11) Reset ECU [11 01] → boots new software
▸ Precondition verification details (step 3): routine 0xFF01 CheckProgrammingPreconditions; ECU checks: vehicleSpeed=0, ignition=ON, engineRunning=FALSE, supplyVoltage=11.0–15.0V, transmissionGear=Park/Neutral; response routineStatusRecord[0]=0x00 (all conditions met) or bit-field of failed conditions; if preconditions fail, programming abort - NRC 0x22 conditionsNotCorrect on 0x10 02; some OEMs require additional [28 03] communicationControl to disable application CAN messages during programming to reduce bus load
▸ Programming session behavioral differences from ExtendedSession: shorter P2/P2* timers (P2=25ms, P2*=5000ms vs 50ms/5000ms in extended); DTC storage suspended (Dem_SetOperationCycleState(CYCLE_IGNITION, DEM_CYCLE_STATE_END)); communication control applied (0x28 03 disables non-diagnostic transmissions); watchdog servicing limited - application stopped, only bootloader/DCM task runs; Aurix TC3xx: PFlash write requires core running in DSPR RAM (execute-in-RAM pattern); voltage monitoring active - reprogramming aborted if supply drops below threshold
▸ OEM variant differences: BMW (EDIABAS/ISTA): uses proprietary 0x31 routines for VCM (Vehicle Configuration Management) pre/post flash; Continental (CGBA): 16-byte seed-key (AES-128 CBC); Bosch (FDL): integrated bootloader with A/B partition support; supplier-specific erase granularity: page erase (2KB Aurix PFlash page) vs sector erase (128KB); total sequence timing on CAN 500kbit/s with 4K blocks: erase 500ms + transfer 512KB × 8ms/block = ~4s transfer + 200ms integrity check; DoIP at 100Mbit/s: same 512KB in <100ms; reference standard: ISO 14229-3 (UDS on CAN), ISO 14229-5 (UDS on Internet Protocol)
RequestDownload / TransferData / TransferExit 55 min read
▸ RequestDownload (0x34) byte structure: [34][dataFormatIdentifier][addressAndLengthFormatIdentifier][memoryAddress...][memorySize...]; dataFormatIdentifier: high nibble = compressionMethod (0=no compression, 1=vendor-specific), low nibble = encryptingMethod (0=no encryption); addressAndLengthFormatIdentifier: high nibble = length of memorySize field (1-4 bytes), low nibble = length of memoryAddress field (1-4 bytes); example: 34 00 44 A0 00 00 00 00 08 00 00 = download to address 0xA0000000, size 0x00080000 (512KB), no compression/encryption; positive response [74][lengthOfMaxBlockSizeParam][maxBlockLen] - tester must split file into blocks ≤ maxBlockLen (e.g., 0x1000 = 4096 bytes per TransferData)
▸ TransferData (0x36) structure: [36][blockSequenceCounter][transferRequestParameterRecord]; blockSequenceCounter starts at 0x01, increments each request, wraps 0xFF → 0x00 (not 0x01); positive response [76][blockSequenceCounter]; data payload = raw binary flash image bytes for that block; ECU writes to flash during 0x36 handler - long write times handled via DCM_E_PENDING callback pattern (P2* timer); if blockSequenceCounter wrong: NRC 0x73 wrongBlockSequenceCounter; if data too long: NRC 0x31 requestOutOfRange; if write fails (bad flash block): NRC 0x72 generalProgrammingFailure; tester must not send next block until positive 0x76 received
▸ TransferExit (0x37) structure: [37][transferRequestParameterRecord (optional, OEM-specific)]; triggers ECU to finalize flash write, flush any write buffers, and prepare for integrity check; positive response [77][transferResponseParameterRecord (optional)]; OEM extensions: Bosch appends CMAC signature in transferRequestParameterRecord for signed download verification; after successful 0x37, tester calls 0x31 01 routineId to verify CRC/checksum; AUTOSAR FBL (Flash Bootloader) Sec module: Sec_VerifySignature(flashStartAddr, flashSize, embeddedSignature) called in 0x31 verify routine; entire download aborted by starting new 0x34 request
▸ Error recovery patterns: on NRC 0x72 (flash write fail): tester must restart from erase (0x31 FF 00) - partial writes leave flash in indeterminate state; on lost communication during 0x36 (CAN bus-off): bootloader detects transfer incomplete via internal state; ECU reset without valid image results in bootloader staying in programming mode (never jumps to application - startup validity check fails); AUTOSAR FBL startup: checks program validity flag in NvM + CRC of each downloaded segment; fallback: dual-bank flash (A/B partition) keeps old valid image in bank B until new image in bank A passes all integrity checks; throughput calculation: 4096-byte block / 8ms (CAN 500kbit/s frame overhead) ≈ 500 KB/s practical throughput
Routine Control (0x31) - Erase, Verify, Check 50 min read
▸ 0x31 service structure: [31][subFunction][routineIdentifier (2B)][routineControlOptionRecord (variable)]; sub-functions: 0x01 startRoutine, 0x02 stopRoutine (for long-running asynchronous routines), 0x03 requestRoutineResults (poll completion status); positive response [71][subFunction][routineIdentifier][routineStatusRecord + routineInfo]; routineStatusRecord[0]: 0x00=routineCompleted-OK, 0x01=routineCompleted-Failed, 0x02=routineStillActive; NRC 0x22 conditionsNotCorrect if routine preconditions not met; NRC 0x31 requestOutOfRange if routineIdentifier not supported
▸ Standardized programming routines: 0xFF00 EraseMemory - routineControlOptionRecord = {addressAndLengthFormatIdentifier, memoryAddress, memorySize}; triggers sector erase (e.g., Aurix PFlash sector = 16KB, UCB not erasable via 0xFF00); must be called in ProgrammingSession + security unlocked; response time: 500ms–2s depending on flash size; 0xFF01 CheckProgrammingDependencies - verifies application software version compatibility with calibration data (CRC match); 0x0202 CheckProgrammingIntegrity (OEM-specific naming varies) - computes CRC32 of downloaded region, compares with expected CRC in routineControlOptionRecord; 0x0203 CheckSoftwareVersion - reads embedded version info from image header
▸ AUTOSAR DCM DcmDspRoutine configuration: DcmDspRoutineIdentifier=0xFF00, DcmDspRoutineSessionRef, DcmDspRoutineSecurityLevelRef; DcmDspRoutineStartFnc=FBL_EraseFlash_Start; DcmDspRoutineStartOutSignal carries routineStatusRecord; for long erase operations (FLASH_ERASE_PENDING): DcmDspRoutineStartFnc returns DCM_E_PENDING → DCM sends NRC 0x78 → calls DcmDspRoutineStartFnc again on next main function cycle; AUTOSAR FBL: HIS (Hersteller Initiative Software) standardized bootloader interface used across German OEMs - defines HIS_MEM_ERASE, HIS_MEM_WRITE, HIS_MEM_READ function signatures called by ECU bootloader UDS handler
▸ CRC integrity check implementation: after 0x37 TransferExit, tester sends [31 01 02 02][expected-CRC32-4bytes]; ECU computes CRC32 (polynomial 0x04C11DB7, init 0xFFFFFFFF, reflect input/output) over downloaded flash region; compares with received expected CRC; mismatch → routineStatusRecord[0]=0x01 (failed) → tester must restart erase + download; successful CRC → ECU sets programValidityFlag in NvM → [11 01] reset triggers bootloader startup validity check → if valid, boot jumps to application; entire flash validation in Aurix: PFLASH module provides hardware CRC accelerator (Crc_CalculateCRC32 API call) - <100ms for 512KB
Flash Bootloader Interaction 45 min read
▸ Application-to-bootloader handover mechanism: application calls Dcm_SetProgConditions(conditions) to store programming context (requestedReset reason, tester logical address, active session) in shared RAM or NvM variable; triggers EcuM_GoDown() or DCM reset via Dcm_TriggerResetToDefaultSession; bootloader on startup reads ProgConditions flag: if set → skip application validity check → stay in bootloader UDS handler; this prevents bootloader from jumping back to application before programming is complete; AUTOSAR: ProgConditions struct defined in Dcm_Types.h (apid, testerSourceAddr, memoryID, fillBuffer) placed in .noinit RAM section (not cleared on reset)
▸ Bootloader memory map (Aurix TC3xx example): PFlash bank 0: 0xA0000000–0xA01FFFFF (2MB); bootloader occupies first 64KB (0xA0000000–0xA000FFFF) - write-protected via Aurix UCB (User Configuration Block) PFlash protection; application occupies 0xA0010000–0xA01FFFFF (1984KB); DFlash (EEPROM emulation): 0xAF000000–0xAF0FFFFF; bootloader config sector: 0xA0000000 offset 0x100 - stores boot vector, CRC, version; UCB_PFLASH protection: sets PFLASHxBWPROT bits to protect bootloader sectors from accidental erase via application SW; AUTOSAR FBL uses HIS memory driver interface: MemDriver_InitSync(), MemDriver_EraseSync(address, length), MemDriver_WriteSync(address, length, buffer)
▸ Bootloader UDS service subset: bootloader implements only essential UDS services - 0x10 (sessions: Default + Programming only), 0x11 (ECUReset), 0x27 (SecurityAccess with programming-level algorithm), 0x28 (CommunicationControl), 0x31 (RoutineControl: erase + check), 0x34 (RequestDownload), 0x36 (TransferData), 0x37 (TransferExit), 0x3E (TesterPresent); bootloader does NOT implement 0x22/0x2E/0x19/0x2F - these return NRC 0x11 (serviceNotSupported); CanTp or DoIP transport configured in bootloader separately from application stack - simpler, hardcoded addressing
▸ Signature verification in bootloader: AUTOSAR Sec module (HIS security module): Sec_VerificationWrapper(dataPtr, dataLength, signaturePtr, signatureLength, publicKeyPtr) → calls SHE CMD_VERIFY_MAC or ECDSA verify; public key stored in OTP (One-Time Programmable) flash or UCB key page; signed data = firmware image hash (SHA-256 of 0x34 download region) + version number; signature appended at end of flash image by build system (ELF post-processing); bootloader parses image header to extract signature offset + length before calling Sec_Verification; if signature invalid: programValidityFlag NOT set → ECU remains in bootloader on next reset → requires new download attempt
Hands-On: Full ECU Reprogramming Sequence 65 min read
▸ Lab setup: CANoe 17 with DoIP simulation bus connected to target ECU (or AUTOSAR simulation node running FBL); load target flash image binary (512KB .bin file); configure tester node: DoIP logical address 0x0E00, ECU logical address 0x1234; verify DoIP Vehicle Announcement on UDP 13400 → TCP routing activation → logical address confirmed; alternatively: CAN500 bus with ISO-TP addressing (physical: tx=0x7E0, rx=0x7E8) and 4KB TransferData blocks
▸ Step-by-step execution with timing measurements: [10 03] open extended session → 50 01 response in 15ms; [27 05] request seed → 67 05 [4-byte seed] in 20ms; compute key using AES-128; [27 06 key] → 67 06 in 10ms (security unlocked); [31 01 FF 01] check preconditions → [71 01 FF 01 00] in 30ms; [10 02] programming session → 50 02 in 10ms; [27 01] + [27 02] programming security access → 10ms each; [31 01 FF 00 44 A0 00 00 00 00 08 00 00] erase 512KB → [71 01 FF 00 00] in 800ms (flash erase time); [34 00 44 A0 00 00 00 00 08 00 00] RequestDownload → [74 20 10 00] (maxBlockLen=0x1000=4096 bytes)
▸ TransferData loop monitoring: 128 iterations of [36 blockCounter 4096 bytes] → [76 blockCounter]; monitor blockSequenceCounter rolls over at 0xFF → 0x00 correctly; measure inter-block timing: CAN 500kbit/s: ~8ms per 4KB block = 1024ms total transfer; DoIP at 100Mbit/s: ~3ms per block = 384ms total; watch for NRC 0x78 response-pending during [31 01 FF 00] erase - handle by extending timeout to 5s; after all blocks: [37] TransferExit → [77] in 50ms; [31 01 02 02 + expectedCRC32] integrity check → [71 01 02 02 00] passed in 200ms; [11 01] hard reset → ECU reboots, boots new firmware
▸ Post-programming validation checklist: after ECU reset, verify [22 F1 86] returns 0x01 (DefaultSession - confirms app running not bootloader); read [22 F1 89] software version DID - compare with expected new version string; send [19 02 08] confirmed DTC check - should return empty (no DTCs stored from programming); run [31 01 FF 01] programming preconditions routine - should pass (confirms ECU in valid operating state); common pitfalls: CRC mismatch due to endianness error in expected CRC calculation, blockSequenceCounter not wrapping correctly causing 0x73 NRC, tester timeout too short for erase (must be >P2* of 5000ms), security key algorithm version mismatch between tester and ECU after software update
6
Production & Aftermarket Diagnostics
5 chapters • 3.8 hrs reading
EOL (End-of-Line) Diagnostic Sequences 40 min read
▸ EOL tester architecture: production-line diagnostic station with PLC controller, CAN/DoIP interface box, and automated test sequence runner (Vector vTESTstudio, CANoe XML scripting, or Python); ECU power-on at station → ECU physical + functional addressing; EOL sequence order: 1) software version check (22 F1 89), 2) hardware number write (2E F1 8A), 3) ECU variant coding write (2E F1 01 = variant byte defining HW configuration), 4) sensor calibration routines (31 01 customerCalibId), 5) actuator test I/O (2F IOControl), 6) final DTC clear (14 FF FF FF), 7) EOL production lock write (2E 0101 = production-complete flag); entire sequence under 60 seconds for high-volume production
▸ Variant coding (0x2E 0xF101): 1-byte or multi-byte value encoding ECU hardware variant (left-hand-drive vs right-hand-drive, engine displacement, market region); stored in DFlash NvM block; DCM validates write against variant mask table (DcmDspDataWriteConditionCheckFnc): checks if variant byte is within allowed OEM-defined range for this ECU hardware part number; OBD mode programming: some OBD jurisdictions (California CARB) require EOL OBD calibration ID write (2E F1 FF = CALID); AUTOSAR DID 0xF101 = ECU Coding Value (standardized in ISO 14229-2)
▸ Calibration routines at EOL: sensor zero-point calibration (e.g., steering angle sensor 0° reference): [31 01 0xA001] with vehicle on alignment rig → ECU captures ADC reading as offset → stores in NvM; actuator end-stop learning (e.g., throttle, EGR valve): [31 01 0xA002] → ECU drives actuator to mechanical stops, measures positions → stores min/max; camera calibration for ADAS (radar/camera alignment): [31 01 0xB001 targetPattern-checksum] → ECU processes pattern via image processing pipeline → writes calibration matrix to NvM; calibration data integrity: CRC protected NvM blocks; routineStatusRecord returned: 00=passed, 01=failed (out-of-range → reject ECU)
▸ EOL security access pattern: production uses separate security level (e.g., 0x09/0x0A) with EOL-specific key - different from after-market service level; EOL key material stored in production tester HSM, never shared with after-market tools; after EOL sequence complete: write EOL-lock DID (2E 0102 = 0x01) → ECU sets NvM flag disabling re-write of variant coding without factory tool; DTC clear (14 FF FF FF) executed last - removes any DTCs triggered by calibration routines; final step: read-back verification of all written DIDs + DTC read confirms clean state; test report auto-generated with pass/fail per step, logged to MES (Manufacturing Execution System)
Tester Present & Keep-Alive Strategies 30 min read
▸ 0x3E TesterPresent service specification: SID 0x3E + subFunction 0x00 (server responds with positive response 0x7E 0x00) or subFunction 0x80 (SPR bit set - suppress positive response, no bus traffic generated); AUTOSAR DCM S3Server timer: DcmTimingP3Client = 5000ms (default ISO 14229 value); S3Server resets on ANY diagnostic request (not just 0x3E) - any request in extended/programming session resets timer; on S3 timeout: DCM transitions to DefaultSession → security level resets to 0x00 → DTC storage re-enabled → communication control reverts
▸ Keep-alive implementation best practice: tester sends [3E 80] every 2000ms (half of S3Server period) to maintain session with zero bus overhead (no response frame); CAPL pattern: on timer tKeepAlive (2000): DiagSendRequest("3E 80"); on diagResponse: (ignored - suppress positive response active); critical: keep-alive must continue during long ECU operations (erase flash, calibration routines) where ECU responds with NRC 0x78 (response-pending); if tester stops 0x3E for >5s during programming session, ECU session drops - bootloader may reset and leave flash in partially erased state
▸ Multi-ECU session management: diagnostic gateway (Central Gateway or DoIP gateway) maintains separate S3Server timers per ECU subnet; gateway receives 0x3E from tester via DoIP and must forward to each ECU that has active extended session; functional addressing (0x7DF on CAN) with [3E 80] broadcasts keep-alive to all ECUs simultaneously with single frame - preferred for multi-ECU scenarios; CANoe gateway simulation: 0x7DF physical → gateway CAPL script → forward to 0x7E0 + 0x6F0 + 0x3B0 (individual ECU addresses); DoIP routing: gateway maps tester DoIP TCP connection sessions to individual ECU CanTp connections, resets S3 per ECU independently
▸ Session persistence pitfalls and debug strategies: symptom: ECU unexpectedly returns to DefaultSession mid-sequence; diagnosis: measure interval between last request and session drop in CANoe trace - if >5000ms, S3Server expired; check: was tester stuck waiting for response (blocking call without timeout) while not sending 0x3E?; solution: run 0x3E keep-alive in separate CAPL timer or Python thread independent of main diagnostic sequence; for python-udsoncan: client.config['p3_client'] = 4.5 (seconds) sets automatic TesterPresent transmission interval; AUTOSAR DcmDspSessionRow: DcmDspSessionP3Time configures per-session S3 timeout; programming session may use shorter timeout (3000ms) to detect lost tester faster
OBD-II & Emission Diagnostics 45 min read
▸ OBD Mode services (SAE J1979 / ISO 15031-5): Mode 01 showCurrentData - PID 0x00 (supported PIDs bitmap), PID 0x05 (coolant temp °C, formula: A-40), PID 0x0C (RPM, formula: (256A+B)/4), PID 0x0D (vehicle speed km/h = A), PID 0x11 (throttle position % = 100A/255); Mode 02 showFreezeFrameData - same PIDs as Mode 01 but at time of last emission DTC set; Mode 03 requestEmissionRelatedDTC - returns J1979 DTC format (2 bytes: first nibble = system A/B/C/U + tens, second byte = DTC sub-code); Mode 04 clearEmissionRelatedDTCs - equivalent to UDS 0x14 for OBD subset; Mode 06 onBoardMonitoringTestResults - OBD monitor IDs with min/max threshold + current value; Mode 09 vehicleInformation - PID 0x02 VIN (17 ASCII chars), PID 0x04 CalibrationID (CALID), PID 0x06 CVN (Calibration Verification Number, CRC)
▸ OBD readiness monitors: ECU maintains 11 readiness flags (Mode 01 PID 0x01 bit map): catalyst monitor, heated catalyst, evaporative system, secondary air, A/C refrigerant, O2 sensor, O2 sensor heater, EGR system, catalyst warmup monitor, misfire (continuous), fuel system (continuous); each monitor = COMPLETE or INCOMPLETE; monitor completes when specific drive cycle conditions met (OBD drive cycle: cold start, warm-up, highway cruise, idle sequence); MIL illuminates when: emission DTC confirmed after 2 failed drive cycles + readiness monitor confirmed failure; AUTOSAR DEM: DemDTCKind=DEM_DTC_KIND_EMISSION_DTC → DEM applies J1979 two-trip confirmation logic; DemOBDRequirements configures readiness group assignments
▸ EOBD vs OBD-II differences: OBD-II (SAE J1979 + EPA CFR Title 40): mandatory USA since 1996; EOBD (ISO 15031 + EU Directive 98/69/EC): mandatory EU since 2000 (gasoline) / 2003 (diesel); EOBD uses same Mode 01-09 protocol; differences: EOBD thresholds for catalyst degradation different from OBD-II; EOBD DTC format identical (J2012 style for standardized emission DTCs: P0xxx, P2xxx, P3xxx0-P3xF); OBD-II requires freeze frame for first emission DTC only; EOBD requires freeze frame for all confirmed emission DTCs; WWH-OBD (ISO 27145 / SAE J1939-73): heavy vehicles - uses DoIP/UDS-based OBD instead of Mode 01-09 (Mode 0x21–0x2A using extended PIDs, DM1/DM2 messages on J1939 PGN 65226)
▸ AUTOSAR DEM OBD configuration: DcmDspObdPid table maps OBD PIDs to data callbacks; DemOBDEngineType (DEM_OBD_ENGINE_COMPRESSION or DEM_OBD_ENGINE_SPARK) enables correct monitor set; DemOBDSupportedMILIndicator links MIL status to DemIndicator; DemWarmUpCycleCounterThreshold (3) for permanent DTC healing; CANoe OBD simulation: insert ELM327 simulation node or use built-in OBD tester panel; read Mode 01 PID 0x41 (monitor status since DTCs cleared) - bit mask shows which monitors completed; IQ-TREE OBD scan tool or Torque Pro app for practical verification; OBD certification testing: PEMS (Portable Emission Measurement System) + OBD monitor completion verification for type approval
Diagnostic Specification (CDD) Authoring 50 min read
▸ CANdelaStudio CDD (CAN Diagnostics Description) file format: XML-based proprietary Vector format (extension .cdd); structure: ECU variant layer (variant-specific overrides) → base variant layer (shared definitions) → protocol layer (ISO 14229 service templates); import workflow: start from OEM DDT-Master CDD (Diagnostic Data Template - OEM-provided base with all standardized DIDs + DTCs) → derive ECU-specific CDD by specializing service table for this ECU's supported services, adding ECU-specific DIDs (0x01xx range), and defining DTC list from AUTOSAR DEM configuration; export: CDD → CANoe Diagnostic description → enables automated tester generation
▸ Service table definition in CDD: for each UDS service, define: SID (hex), supported sub-functions list, session mask (DefaultSession/ExtendedDiagnosticSession/ProgrammingSession bitmask), security level mask (level 0x01, 0x03 etc.), request/response signal layout with data type (uint8/uint16/BCD), scaling (formula A*factor+offset), unit, and min/max range; DID table: DID identifier (e.g., 0xF190 VIN), data length (17 bytes), data type (ASCII), read-only vs read-write, session/security constraints; DTC table: DTC code (3-byte hex), DTC description string (e.g., "Overvoltage Battery"), functional group (Powertrain/Body/Chassis), severity, snapshot DID references
▸ ODX (Open Diagnostic Data Exchange, ISO 22901) as standardized alternative to CDD: ODX files = XML with defined schema; layers: BASE-VARIANT (manufacturer-common), ECU-VARIANT (per ECU), PROTOCOL (ISO 14229 service model), FUNCTIONAL-GROUP (DTC grouping); tools: ETAS EDIABAS/INPA uses .GRP/.PRG files (proprietary), Softing OBD Middleware uses ODX; AUTOSAR migration: AUTOSAR ARXML diagnostic extract can be imported into CANdelaStudio to auto-generate CDD from AUTOSAR DCM configuration - maintains single source of truth; version control: CDD versioning managed in CDD header (author, version string, creation date); variant management: CDD branches per ECU software variant with diff visualization in CANdelaStudio Variant Manager
▸ Practical CDD authoring workflow: 1) receive OEM DDT-Master CDD → open in CANdelaStudio; 2) create ECU-variant layer, inherit base variant; 3) add ECU-specific supported service list (delete services this ECU doesn't support); 4) import DID list from AUTOSAR DCM ARXML (File → Import → AUTOSAR DCM); 5) map DEM DTC list to CDD DTC table - each DemEventParameter becomes one DTC row; 6) define snapshot DIDs per DTC (reference CDD DID definitions); 7) define security access key algorithm reference (DLL name for tester); 8) export as CANoe DDC (Diagnostic Description Container) → load in CANoe → generate automated test sequences; validation: CANoe Diagnostic Symbol Explorer verifies no missing mandatory services per OEM DSSAD (Diagnostic Service Specification and Approval Document)
Hands-On: Production Diagnostic Tester 60 min read
▸ Python production tester architecture: pip install python-udsoncan python-can; imports: import udsoncan, can, udsoncan.connections as conn; create socketcan or PCAN interface: bus = can.interface.Bus('can0', bustype='socketcan', bitrate=500000); transport = conn.PythonIsoTpConnection(bus, rxid=0x7E8, txid=0x7E0, address_type=udsoncan.TargetAddressType.Physical); config: {'request_timeout':2, 'p3_client':4.5, 'use_server_timing':True}; client = udsoncan.Client(transport, config=config); entire sequence wrapped in context manager: with client: ... handles connection + TesterPresent keep-alive automatically via config p3_client interval
▸ Step-by-step Python implementation: client.change_session(DiagnosticSessionControl.Session.extendedDiagnosticSession); # Security access with customer algorithm: response = client.request_seed(0x09); seed = response.service_data.seed; key = production_key_algorithm(seed, SECRET_MASTER_KEY); client.send_key(0x09, key); # Read VIN for verification: vin_response = client.read_data_by_identifier([0xF190]); vin = vin_response.service_data.values[0xF190].decode('ascii'); # Write variant code: client.write_data_by_identifier(0xF101, bytes([VARIANT_CODE])); # Trigger EOL calibration routine: client.start_routine(0xA001); routine_result = client.request_routine_results(0xA001); assert routine_result.service_data.routine_status_record[0] == 0x00; # Clear DTCs: client.clear_dtc(0xFFFFFF); # Final DTC check: dtcs = client.get_dtc_by_status_mask(0x08); assert len(dtcs) == 0, f"Unexpected confirmed DTCs: {dtcs}"
▸ Quality gate pass/fail logic: define test_results = {} dictionary; for each step assign pass/fail with actual vs expected value; generate structured report: {timestamp, ECU_partNumber, testerSerialNumber, step_results: [{step:'VIN', expected:'WBA12345678901234', actual:vin, pass:True}, {step:'VariantCode', expected:0x03, actual:written_code, pass:True}, {step:'CalibrationRoutine', expected:0x00, actual:routine_result, pass:True}, {step:'DTCCheck', expected:0, actual:0, pass:True}]}; write JSON report to shared network path for MES integration; barcode scanner integration: scan ECU barcode → set PART_NUMBER + VIN variables → run sequence → upload report to quality database; target cycle time: <30 seconds per ECU including power-on delay
▸ Common pitfalls and debugging: NRC 0x22 on session change → ECU voltage too low (<10.5V), check bench supply; NRC 0x36 on security access → key algorithm mismatch - verify MASTER_KEY version matches ECU software version (version tied to key variant); NRC 0x31 on variant write → variant code out of allowed range for this hardware part number - check OEM variant matrix; NRC 0x78 unexpected during routine → extend routine timeout to 10s for slow NvM writes; IsoTP timeout on TransferData → CAN bus overloaded - check no other nodes transmitting; use python-can Bus.set_filters() to capture all diagnostic frames for post-mortem analysis; dump full session trace with can.Logger('test_trace.asc') → open in CANoe for timing analysis

What You'll Learn

Implement all major UDS services per ISO 14229
Design DTC management strategies with proper aging/priority
Configure security access with seed & key algorithms
Execute complete ECU reprogramming sequences
Author production-grade diagnostic specifications
Debug diagnostic communication issues on CAN and DoIP

Prerequisites

Basic understanding of CAN protocol
Familiarity with hexadecimal data representation
Some experience with automotive ECU concepts
Full Access
Free with Pro
Enroll Now Browse Modules

This course includes:

32 detailed documentation chapters
Downloadable resources
Searchable text documentation
Code snippets & technical diagrams
Hands-on exercises
Lifetime access
Certificate of completion