/* UDS 0x31 0x01 0xFF00: EraseMemory */
/* Request: 0x31 0x01 0xFF 0x00 [address 4 bytes] [length 4 bytes] */
/* Response: 0x71 0x01 0xFF 0x00 (when complete) */
/* During erase: 0x7F 0x31 0x78 (NRC responseePending, repeated every 2.5s) */
#include "Flash_If.h"
#include "Dcm_Cbk.h"
typedef enum {
ERASE_IDLE = 0u,
ERASE_IN_PROGRESS = 1u,
ERASE_DONE_OK = 2u,
ERASE_DONE_ERR = 3u,
} EraseState_t;
static EraseState_t g_erase_state = ERASE_IDLE;
static uint32_t g_erase_addr;
static uint32_t g_erase_len;
/* DCM calls this; returns PENDING if erase still running */
Std_ReturnType RC_EraseMemory(const uint8_t *req, uint16_t req_len,
uint8_t *resp, uint16_t *resp_len,
Dcm_OpStatusType op_status)
{
if (op_status == DCM_INITIAL) {
/* First call: parse parameters and start erase */
g_erase_addr = ((uint32_t)req[4]<<24)|((uint32_t)req[5]<<16)
|((uint32_t)req[6]<<8)| (uint32_t)req[7];
g_erase_len = ((uint32_t)req[8]<<24)|((uint32_t)req[9]<<16)
|((uint32_t)req[10]<<8)| (uint32_t)req[11];
if (!Flash_IsErasable(g_erase_addr, g_erase_len)) {
resp[0]=0x7Fu; resp[1]=0x31u; resp[2]=0x31u; /* NRC requestOutOfRange */
*resp_len = 3u; return E_NOT_OK;
}
Flash_StartErase(g_erase_addr, g_erase_len); /* non-blocking start */
g_erase_state = ERASE_IN_PROGRESS;
return DCM_E_PENDING; /* DCM will send NRC 0x78 and call us again */
}
/* Subsequent calls: check status */
if (g_erase_state == ERASE_IN_PROGRESS) {
Flash_MainFunction(); /* drive flash state machine */
MemIf_StatusType status = Flash_GetStatus();
if (status == MEMIF_BUSY) {
Wdg_Trigger();
return DCM_E_PENDING; /* still erasing; DCM sends another 0x78 */
}
g_erase_state = (status == MEMIF_IDLE) ? ERASE_DONE_OK : ERASE_DONE_ERR;
}
if (g_erase_state == ERASE_DONE_OK) {
resp[0]=0x71u; resp[1]=0x01u; resp[2]=0xFFu; resp[3]=0x00u;
*resp_len = 4u; return E_OK;
}
resp[0]=0x7Fu; resp[1]=0x31u; resp[2]=0x72u; /* NRC uploadDownloadNotAccepted */
*resp_len = 3u; return E_NOT_OK;
}RoutineControl 0xFF00: EraseMemory
RoutineControl 0xFF01: CheckProgrammingDependencies
/* UDS 0x31 0x01 0xFF01: CheckProgrammingDependencies */
/* Run after all TransferData blocks complete + RequestTransferExit */
/* Verifies: CRC, SW version compatibility, memory bounds, signature */
#include "Flash_If.h"
#include "Crypto.h"
/* Routine 0xFF01 result codes (OEM-defined; returned in routine result) */
#define CHECK_RESULT_OK 0x00u
#define CHECK_RESULT_CRC_FAIL 0x01u
#define CHECK_RESULT_SIG_FAIL 0x02u
#define CHECK_RESULT_DEP_FAIL 0x03u
Std_ReturnType RC_CheckProgramming(uint8_t *result_code)
{
const AppHeader_t *hdr = (const AppHeader_t *)APP_BASE;
/* Check 1: Magic number */
if (hdr->magic != APP_MAGIC) {
*result_code = CHECK_RESULT_CRC_FAIL;
return E_NOT_OK;
}
/* Check 2: CRC-32 over application code */
uint32_t computed_crc = Crc_CalculateCRC32(
(const uint8_t *)(APP_BASE + sizeof(AppHeader_t)),
hdr->app_length, CRC32_INIT, TRUE);
if (computed_crc != hdr->app_crc32) {
*result_code = CHECK_RESULT_CRC_FAIL;
return E_NOT_OK;
}
/* Check 3: Cryptographic signature (if secure boot enabled) */
/* Verify ECDSA P-256 signature in header against public key in PBL */
if (SecureBoot_VerifySignature(hdr) != E_OK) {
*result_code = CHECK_RESULT_SIG_FAIL;
return E_NOT_OK;
}
/* Check 4: Compatibility with bootloader version */
if ((hdr->bootloader_version & 0xFFFF0000u) !=
(PBL_VERSION & 0xFFFF0000u)) {
*result_code = CHECK_RESULT_DEP_FAIL;
return E_NOT_OK;
}
*result_code = CHECK_RESULT_OK;
/* Mark application as valid: write valid signature to boot flags */
BootFlags_SetAppValid();
return E_OK;
}Summary
RoutineControl 0xFF00 (erase) and 0xFF01 (check) are the two mandatory AUTOSAR-defined programming routines. The erase routine uses the DCM_E_PENDING mechanism to handle long erase times: DCM automatically sends NRC 0x78 (responsePending) every 2.5 seconds while the routine returns DCM_E_PENDING, preventing the tester's P2* timer from expiring. The check routine (0xFF01) is the final gate before ECUReset: it validates CRC integrity, cryptographic signature, and bootloader compatibility — if any check fails, the application is rejected and the ECU stays in reprogramming mode rather than booting a corrupt or malicious image.
🔬 Deep Dive — Core Concepts Expanded
This section builds on the foundational concepts covered above with additional technical depth, edge cases, and configuration nuances that separate competent engineers from experts. When working on production ECU projects, the details covered here are the ones most commonly responsible for integration delays and late-phase defects.
Key principles to reinforce:
- Configuration over coding: In AUTOSAR and automotive middleware environments, correctness is largely determined by ARXML configuration, not application code. A correctly implemented algorithm can produce wrong results due to a single misconfigured parameter.
- Traceability as a first-class concern: Every configuration decision should be traceable to a requirement, safety goal, or architecture decision. Undocumented configuration choices are a common source of regression defects when ECUs are updated.
- Cross-module dependencies: In tightly integrated automotive software stacks, changing one module's configuration often requires corresponding updates in dependent modules. Always perform a dependency impact analysis before submitting configuration changes.
🏭 How This Topic Appears in Production Projects
- Project integration phase: The concepts covered in this lesson are most commonly encountered during ECU integration testing — when multiple software components from different teams are combined for the first time. Issues that were invisible in unit tests frequently surface at this stage.
- Supplier/OEM interface: This is a topic that frequently appears in technical discussions between Tier-1 ECU suppliers and OEM system integrators. Engineers who can speak fluently about these details earn credibility and are often brought into critical design review meetings.
- Automotive tool ecosystem: Vector CANoe/CANalyzer, dSPACE tools, and ETAS INCA are the standard tools used to validate and measure the correct behaviour of the systems described in this lesson. Familiarity with these tools alongside the conceptual knowledge dramatically accelerates debugging in real projects.
⚠️ Common Mistakes and How to Avoid Them
- Assuming default configuration is correct: Automotive software tools ship with default configurations that are designed to compile and link, not to meet project-specific requirements. Every configuration parameter needs to be consciously set. 'It compiled' is not the same as 'it is correctly configured'.
- Skipping documentation of configuration rationale: In a 3-year ECU project with team turnover, undocumented configuration choices become tribal knowledge that disappears when engineers leave. Document why a parameter is set to a specific value, not just what it is set to.
- Testing only the happy path: Automotive ECUs must behave correctly under fault conditions, voltage variations, and communication errors. Always test the error handling paths as rigorously as the nominal operation. Many production escapes originate in untested error branches.
- Version mismatches between teams: In a multi-team project, the BSW team, SWC team, and system integration team may use different versions of the same ARXML file. Version management of all ARXML files in a shared repository is mandatory, not optional.
📊 Industry Note
Engineers who master both the theoretical concepts and the practical toolchain skills covered in this course are among the most sought-after professionals in the automotive software industry. The combination of AUTOSAR standards knowledge, safety engineering understanding, and hands-on configuration experience commands premium salaries at OEMs and Tier-1 suppliers globally.