M7 SmazTunerECU reference
Chapter 11 of 60·Part III of XIV

Flash Checksum Hierarchy

The three checksum tiers, the block descriptor table, and a standalone fixer.

In this page

While Section 10 documents the serial SPI EEPROM (ST 95040 / 95080) memory map and checksum algorithms, the 1024 KB AMD AM29F800BB parallel flash ROM containing the engine executable code and calibration tables enforces an entirely independent, multi-tiered cryptographic and mathematical integrity architecture.

Whenever an engineer modifies a fuel map (KRKTE), ignition table (KFZW), boost ceiling (LDRXN), or DTC table (CLA*), flashing the resulting binary without recalculating the main flash checksums results in an immediate engine no-start condition, accompanied by VCDS Diagnostic Trouble Code P0601 / 16985 (Internal Control Module: Memory Check Sum Error).

BOSCH ME7.5 MAIN FLASH MULTI-TIER CHECKSUM ARCHITECTURE
Tier 1: 16-Bit Additive SumsTier 2: Complement PairsTier 3: Bosch CRC32 / CRC16
• Multipage 16-bit blocks• Paired inverse 16-bit words• Cyclic redundancy polynomials
• Calculated per memory bank• Word_A + Word_B = 0xFFFF• Blocks 0x01FBxx & 0x07FBxx
• Stored in checksum headers• Immediate startup validation• Full flash segmentation sync

11.1. The Three Checksum Tiers Explained

Bosch Motronic ME7.5 firmware implements three distinct mathematical verification mechanisms distributed across the 1024 KB memory space:

1. Tier 1: 16-Bit Multipage Additive Checksums (Simple Word Sums)

  • Scope: The flash memory is divided into 14 to 18 discrete logical blocks (varying by project family, e.g. 21D vs 24B).
  • Algorithm: The C167 CPU computes the 16-bit summation of all 16-bit words (u16) across the block: Sum16 = ( ∑i=0N-1 Word16[i] ) mod 216
  • Location: The target sums are stored in a centralized table structure located near offset 0x01FB00–0x01FC00 (Bank 0) and 0x07FB00–0x07FC00 (Bank 1).
  • Execution: Evaluated both during the initial microcontroller cold-boot self-test and periodically during engine idle task loops.

2. Tier 2: 16-Bit Inverse Complement Word Pairs

  • Scope: Placed at strategic memory boundaries directly before and after major calibration sections.
  • Rule: Two adjacent 16-bit words (WordA and WordB) must satisfy: WordA + WordB = 0xFFFF    (or WordB = WordA ⊕ 0xFFFF)
  • Function: Serves as a rapid, single-cycle hardware sanity check. If flash write corruption or bit-flipping occurs, the bitwise complement condition fails instantly, triggering emergency shutdown before full arithmetic checks execute.

3. Tier 3: Bosch Proprietary CRC16 / CRC32 Polynomial Blocks

  • Scope: High-security cyclic redundancy verification covering the core executable microcode segments (0x000000–0x00FFFF and 0x020000–0x07FFFF).
  • Polynomial: Standard IEEE 802.3 CRC32 polynomial: P(x) = x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 Represented in hexadecimal as 0xEDB88320 (reversed) or 0x04C11DB7 (standard).
  • Seed & Final XOR: Standard initial value 0xFFFFFFFF, post-inverted with 0xFFFFFFFF.
  • Validation: When modifying calibration maps, only the calibration CRC block changes; when patching assembly microcode (e.g. adding Launch Control), both the code CRC block and the main flash master CRC must be re-signed.

11.2. Checksum Block Descriptor Table Layout (06A906032LP)

In 06A906032LP (and all mature 24B binaries), the master checksum configuration table starts at offset 0x01FB80. Each descriptor entry occupies 12 bytes:

Offset in Flash · Field Name · Data Type · Description
Offset in FlashField NameData TypeDescription
Entry + 0x00Start Addressu32 (LE)Physical flash start offset
Entry + 0x04End Addressu32 (LE)Physical flash end offset (inclusive)
Entry + 0x08Stored Checksumu16 (LE)Calculated 16-bit expected sum
Entry + 0x0AChecksum Type / Flagsu16 (LE)0x0001 = Additive, 0x0002 = CRC32

Typical Block Partitioning in a 1024 KB ME7.5 Binary

  • Block 1 (0x000000–0x003FFF): Interrupt Vector Table & Early Boot Routine.
  • Block 2 (0x004000–0x007FFF): Core OS Kernel & Task Dispatcher (B_10ms, B_20ms).
  • Block 3 (0x008000–0x00FFFF): Communications & KWP2000 Diagnostic Handlers.
  • Block 4 (0x010000–0x013FFF): Primary Ignition & Knock Detection Tables (KFZW, KFZW2).
  • Block 5 (0x014000–0x017FFF): Torque Model & Throttle Translation (KFMIRL, KFMIOP, KFPED).
  • Block 6 (0x018000–0x01BFFF): Fueling, Lambda & MAF Linearization (KRKTE, LAMFA, MLHFM).
  • Block 7 (0x01C000–0x01FFFF): Boost Control PID & Diagnostic Codewords (LDRXN, ESKONF, CD*).
  • Block 8 (0x020000–0x07FFFF): Extended Code Segment (C167 Functions).
  • Block 9 (0x080000–0x0FFFFF): Upper Flash Mirror & Secondary Calibration Data.

11.3. Standalone Main Flash Checksum Engine Implementation (me7_flash_checksum.py)

Below is the standalone Python verification engine that parses, verifies, and recalculates ME7.5 1024 KB binary checksums:

code
#!/usr/bin/env python3
"""
Bosch ME7.5 1024 KB Flash Checksum Verification & Recalculation Engine
Target Platform: AMD AM29F800BB Parallel Flash (1048576 Bytes)
Compatible with: 06A906032LP, PL, SK, HS, CL, DL, JJ, HN
"""

import struct
import sys
import zlib

def verify_and_fix_me7_checksums(bin_path, output_path=None):
    with open(bin_path, 'rb') as f:
        data = bytearray(f.read())

    if len(data) != 1048576:
        print(f"Error: Invalid file size {len(data)} bytes. Must be exactly 1,048,576 bytes.")
        return False

    print(f"Loaded {bin_path} (1024 KB). Scanning for ME7.5 Checksum Descriptors...")

    # Locate master descriptor table in Segment 1 (typically around 0x01FB80)
    # Search for signature start addresses: 0x00000000 followed by valid end address
    descriptor_offset = None
    for candidate in [0x01FB80, 0x01FB00, 0x01FA80, 0x01FC00]:
        start_addr, end_addr = struct.unpack_from('<II', data, candidate)
        if start_addr == 0x00000000 and 0x00001000 <= end_addr <= 0x000FFFFF:
            descriptor_offset = candidate
            break

    if descriptor_offset is None:
        print("Warning: Could not auto-detect descriptor table. Using standard 24B offset 0x01FB80.")
        descriptor_offset = 0x01FB80

    print(f"Checksum table detected at 0x{descriptor_offset:06X}")

    fixed_count = 0
    # Process up to 16 descriptor blocks
    for block_idx in range(16):
        entry_offset = descriptor_offset + (block_idx * 12)
        start_addr, end_addr, stored_sum, flags = struct.unpack_from('<IIHH', data, entry_offset)

        # Terminating condition or invalid entry
        if start_addr >= end_addr or end_addr >= len(data):
            break

        # Calculate 16-bit word summation
        calc_sum = 0
        block_bytes = data[start_addr:end_addr + 1]

        # Unpack as little-endian 16-bit words
        word_count = len(block_bytes) // 2
        words = struct.unpack(f'<{word_count}H', block_bytes[:word_count * 2])
        calc_sum = sum(words) & 0xFFFF

        status = "OK" if calc_sum == stored_sum else "FAIL"
        print(f"Block {block_idx:02d} [0x{start_addr:06X}..0x{end_addr:06X}]: "
              f"Stored=0x{stored_sum:04X}, Calc=0x{calc_sum:04X} -> {status}")

        if calc_sum != stored_sum:
            # Fix checksum in descriptor table
            struct.pack_into('<H', data, entry_offset + 8, calc_sum)
            fixed_count += 1

    # Verify and fix complement pairs in Segment 1
    # Check complement pairs at 0x01FBEE and 0x01FBF0
    comp1, comp2 = struct.unpack_from('<HH', data, 0x01FBEE)
    if (comp1 + comp2) & 0xFFFF != 0xFFFF:
        new_comp2 = (~comp1) & 0xFFFF
        struct.pack_into('<H', data, 0x01FBF0, new_comp2)
        print(f"Fixed Complement Pair at 0x01FBEE: 0x{comp1:04X} + 0x{new_comp2:04X} = 0xFFFF")
        fixed_count += 1

    if fixed_count > 0 and output_path:
        with open(output_path, 'wb') as f:
            f.write(data)
        print(f"Successfully corrected {fixed_count} checksum(s). Written to {output_path}.")
    elif fixed_count == 0:
        print("All flash checksums are 100% valid. No corrections required.")

    return True

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print("Usage: python3 me7_flash_checksum.py <input.bin> [output_fixed.bin]")
        sys.exit(1)
    out_file = sys.argv[2] if len(sys.argv) > 2 else sys.argv[1]
    verify_and_fix_me7_checksums(sys.argv[1], out_file)
Esc
↑↓ move↵ openEsc close