|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Last refreshed: 2026-05-03 (refresh stamp recorded for audit-trail consistency with the rest of the qualification document set; design- level descriptions did not require number changes).
Status: First draft, 2026-05-02. Authored against the Phase 7 schedule in ../QUALIFICATION_ROADMAP.md Section 3. DO-178C reference: Section 11.10 (Design Description). IEC 61508-3 reference: Clause 7.4 (Software design and development). ISO 26262-6 reference: Clause 7 (Software architectural design) and Clause 8 (Software unit design). Project: ra8-firmware. Maintainer: Brighton Sikarskie (single developer).
This SDD is the design-level companion to the requirements in ./SRS.md. It explains how the codebase satisfies each REQ-XXX item: which module owns each requirement, which lower-ring modules it consumes, what data it persists, and which algorithm / state machine the implementation runs.
The architectural baseline of seven rings + three TrustZone worlds is established in ../RING_AND_WORLD.md; this SDD does not duplicate that text – it consumes it. Section 1 below points into the relevant chapters of the existing design corpus rather than re-stating them.
Per ../RING_AND_WORLD.md:
| Ring | Layer | Index entry | Owns REQ family |
|---|---|---|---|
| 0 | BSP boot | libs/ra8_board_<board>/{src/boot,ld}/ with explicit app-local src/ overrides | REQ-CHIP-XXX |
| 1 | Core utilities | ../../libs/ra8_core/ | REQ-CORE-XXX |
| 2 | Register layouts | ../../libs/ra8_hal/inc/ra8_*_regs.h (live glob authority) | REQ-CHIP-006 |
| 3 | HAL drivers | ../../libs/ra8_hal/src/ + PALs | REQ-DRV-XXX, REQ-HAL-XXX |
| 4 | NSC veneers | ../../libs/ra8_nsc/ | REQ-PORT-001..009 |
| 5 | Secure-app | ../../libs/ra8_secure_app/ | REQ-PORT-010..013 |
| 6 | Application | ../../examples/ek_ra8d2/ and ../../examples/ra8p1_foundation/; the live selection comes from scripts/dev/ra8_apps.py | REQ-APP-XXX |
Higher rings may include lower-ring headers freely; the inverse is a layering violation rejected by scripts/checks/check_world_tags.py. This is the design-rule basis for IEC 61508-3 Clause 7.4.3.
Three worlds: S (Secure), NS (Non-Secure), NSC (Non-Secure- Callable veneer surface). The boundary is enforced by the SAU configuration from the selected board layer, unless an app explicitly overrides trustzone_init.c. All NSC entry points carry __attribute__((cmse_nonsecure_entry)) and SHALL live under ../../libs/ra8_nsc/ (REQ-PORT-001).
Each step is owned by a single TU. The selected board linker script (or explicit app-local override) and the __attribute__((constructor)) order in ra8_infrastructure.c enforce the transitions.
Each module = one subdirectory under libs/. The columns are:
| Module | Public API (libs/ra8_core/inc/) | Internal | Depends on | Consumed by | Implements |
|---|---|---|---|---|---|
| ra8_core | ra8_err.h, ra8_check.h, ra8_log.h, ra8_time.h, ra8_time_interface.h, ra8_pin_interface.h, ra8_pin_validator.h, ra8_register_guard.h, ra8_exception.h, ra8_error_handler.h, ra8_error_interface.h, ra8_infrastructure.h, ra8_stack_budget.h, ra8_bit_constants.h, ra8_gpio_constants.h, ra8_port_constants.h, ra8_time_constants.h, ra8_off_target_config.h | - | (none) | every Ring 2/3 driver | REQ-CORE-001..014 |
Notes:
| Module | Public API | Implements |
|---|---|---|
| ra8_hal/regs | libs/ra8_hal/inc/ra8_*_regs.h (live glob authority) | REQ-CHIP-006 (every base address declared as uintptr_t typed enum per CLAUDE.md) |
The full per-driver enumeration is the REQ-DRV-XXX table in ./SRS.md Section 4.3. Each driver TU is the smallest testable unit; one driver = one REQ-DRV row = one host test.
Cross-cutting design points:
| Module | Public API (module inc/) | Depends on (Ring 3 drivers) | Implements |
|---|---|---|---|
| ra8_gfx | ra8_gfx.h, ra8_gfx_font.h | ra8_glcdc | REQ-HAL-001 |
| ra8_fs | ra8_fs.h | block-device backends (ra8_sdhi, ra8_sdmmc_spi, ra8_xspi, LevelX via port/levelx/) | REQ-HAL-002 |
| ra8_mpu | ra8_mpu.h | core MPU regs (Ring 2) | REQ-HAL-003 |
| ra8_wdt_supervisor | ra8_wdt_supervisor.h | ra8_iwdt, ra8_wdt | REQ-HAL-004 |
| ra8_power_profile | ra8_power_profile.h | ra8_lpm, ra8_pwr, ra8_vreg | REQ-HAL-005 |
| ra8_net_pal | ra8_net_pal.h | ra8_eth*, ra8_usb_hcdc_ecm, ra8_modem_at | REQ-HAL-006 |
| ra8_usb_pal | ra8_usb_pal.h | ra8_usb and class drivers | REQ-HAL-007 |
| NetX Duo port | port/netxduo/inc/nx_ether_driver_ra8_eth.h | ra8_net_pal, ra8_eth*, NetX Duo (SOUP) | REQ-HAL-008 |
| ra8_tls | ra8_tls.h | Mbed TLS (SOUP), ra8_psa_crypto | REQ-HAL-009 |
| ra8_psa_crypto | ra8_psa_crypto.h | TF-PSA-Crypto (SOUP), ra8_rsip* (when HW path available) | REQ-HAL-010 |
| ra8_ota | ra8_ota.h | ra8_flash, ra8_psa_crypto, NSC ra8_nsc_ota | REQ-HAL-011 |
| NimBLE host (SOUP, via port/nimble) | NimBLE host/ble_*.h (libs/third_party/nimble/) | ra8_ble (HCI transport seam; controller on ESP32-C6 companion), Apache NimBLE (SOUP) | REQ-HAL-012 |
| ra8_modem_at | ra8_modem_at.h | injected byte-stream operations (ra8_io_stream_uart in production) | REQ-HAL-013 |
| epub | apps/shared_libs/epub/inc/epub.h | ra8_fs, miniz (SOUP), TinyXML-2 (SOUP) via xml shim | REQ-HAL-014 |
| reflow | apps/shared_libs/reflow/inc/reflow.h | ra8_gfx, litehtml (SOUP) via xml shim | REQ-HAL-015 |
| ra8_touch_cal | (header only, no public API beyond the calibration call) | ra8_touch | REQ-HAL-016 |
| Module | Public API | Depends on | Implements |
|---|---|---|---|
| ra8_board_ek_ra8d2 | ra8_board_ek_ra8d2.h | ra8_cgc, ra8_sdramc, ra8_glcdc, ra8_mpc, gpio.c, ra8_pin_validator | REQ-BSP-001..004 |
| Module | Public API (libs/ra8_nsc/inc/) | Implements |
|---|---|---|
| ra8_nsc | ra8_nsc.h, ra8_nsc_comms.h, ra8_nsc_io.h, ra8_nsc_veneer.h | REQ-PORT-001..009 (one veneer TU per row, see SRS Section 4.6) |
Each veneer TU contains exactly one __attribute__((cmse_nonsecure_entry)) function group; __cmse_nonsecure_entry outside this directory is rejected by check_world_tags.py.
| Module | Header (libs/ra8_secure_app/) | Implements |
|---|---|---|
| key_vault | libs/ra8_secure_app/inc/key_vault.h | REQ-PORT-010 (256-bit symmetric key store) |
| key_import | libs/ra8_secure_app/src/key_import_internal.h | REQ-PORT-011 (wrapped-blob import + key-class enum) |
| ota_commit | libs/ra8_secure_app/inc/ota_commit.h | REQ-PORT-012 (atomic MRAM bank swap) |
| secure_trng | libs/ra8_secure_app/src/secure_trng_internal.h | REQ-PORT-013 (entropy source for PSA-Crypto) |
Each selected app owns its Ring 6 examples/ek_ra8d2/<tier>/.../<app>/src/main.c (or the RA8P1 equivalent) and thin root CMake declaration. The selected board layer supplies the default Ring 0 boot files and linker script; an app-local src/ boot file or root linker_script.ld explicitly overrides that default when its boot or memory map must diverge. The authoritative inventory is derived at gate time by scripts/dev/ra8_apps.py; bidirectional REQ-APP trace remains an open evidence item in ./SRS.md Section 4.7.
The authoritative memory map is ../MEMORY_MAP.md. The salient SDD-level placement decisions are:
| Region | Base | Use | Sizing source |
|---|---|---|---|
| ITCM (64 KiB) | 0x00000000 | Hot-path code marked __attribute__((section(".itcm.text"))) in selected TUs. | Fixed by silicon. |
| MRAM-S (1 MiB) | 0x02000000 | .vectors, .text, .rodata, OFS bytes. Linker script in each app. | Fixed by silicon. |
| MRAM-NS alias | 0x02080000 | NS image alias for the single-image TrustZone build. | Linker script. |
| DTCM (64 KiB) | 0x20000000 | DMA descriptor pools, ra8_log ring buffer, scratch tied to ISR fast paths. | Per-app linker script. |
| SRAM-S (1664 KiB) | 0x22000000 | .data, .bss, ThreadX pools (when ThreadX is linked), framebuffers spilled out of SDRAM. | libs/ra8_core/inc/ra8_device.h |
| SRAM-NS alias (640 KiB) | 0x22100000 | NS-side .data/.bss for the single-image build. | Linker script. |
| SDRAM (64 MiB) | 0x68000000 | Primary framebuffer (1024x600x4 = 2.34 MiB per layer x N), GLCDC layer ping-pong. | ra8_sdramc.c, ra8_glcdc.c. |
| Octo-SPI XIP | (TBD enum) | Optional XIP read window for large rodata blobs (apps that need it). | ra8_xspi.c. |
| Peripheral window | 0x40000000 | Hand-written register layouts in libs/ra8_hal/inc/ra8_*_regs.h. | HUM Ch 7+. |
| Core MPU regs | 0xE000ED90 | Cortex-M85 MPU control accessed by libs/ra8_mpu/. | Armv8-M ARM. |
Per-task stack sizes are declared in ../../libs/ra8_core/inc/ra8_stack_budget.h and reproduced in ../STACK_USAGE.md. The -fstack-usage outputs (*.su files) are aggregated by scripts/checks/stack_usage_check.py. Build fails if any function exceeds its declared bucket (REQ-PERF-008).
| Asset | Location | Owner |
|---|---|---|
| Active firmware image | MRAM bank A or B at 0x02000000 | libs/ra8_ota/ + libs/ra8_secure_app/src/ota_commit.c |
| Wrapped key blobs | Last MRAM block, S-only | libs/ra8_secure_app/src/key_import.c + key_vault.c |
| OFS bytes | MRAM offset per HUM Ch 6 | libs/ra8_hal/src/ra8_ofs.c + per-app linker script |
| TSN factory cal | 0x02C1EDA0 | libs/ra8_hal/src/ra8_tsn.c |
| External NOR (LevelX-backed) | xSPI memory window | LevelX SOUP via port/levelx/ + libs/ra8_cache_store/ |
| External SD card data | FAT volume on SD-card via SDHI | first-party libs/ra8_fs/src/ra8_fs_fat.c |
All compile-time configuration is C23 typed enums per ../../CLAUDE.md "Constants and Macros". No EEPROM-backed parameter file is in scope (PSAC Section 7.4).
Cross-ring calls SHALL go from a higher ring to a strictly lower ring (N -> M with M < N). The check is enforced by scripts/checks/check_world_tags.py reading the per-file [Ring X / ...] header tags. scripts/checks/cite_check.py audits the corresponding @cite HUM-Ch-NN references on Ring 2/3 TUs.
Every public API across rings honours:
NSC veneers SHALL:
The current pattern is shown in ../../libs/ra8_nsc/src/ra8_nsc_comms.c and tested in ../../tests/net/src/test_ra8_nsc_comms.c.
States: idle -> fetching -> staged -> verifying -> committing -> done. Failure transitions return to idle with the cause logged via ra8_log_error. Implementation: libs/ra8_ota/src/ra8_ota.c. Test: tests/misc/src/test_ra8_ota.c.
States follow the standard USB enumeration FSM: attached -> powered -> default -> address -> configured -> suspended/resumed/disconnected. Implementation in ra8_usb.c + ra8_usb_cdc.c. Test: tests/usb/src/test_ra8_usb_cdc.c.
The BLE host is Apache NimBLE (SOUP, libs/third_party/nimble/), consumed directly by applications through the port/nimble/ ThreadX + HCI-over-ra8_ble port; the former first-party BLE-host facade was retired. NimBLE runs the host and the ESP32-C6 companion runs the controller across the HCI transport seam. End-to-end coverage is HW-blocked (REQ-HAL-012): on-wire BLE needs the ESP32-C6 companion. The HCI transport seam (ra8_ble) is tested in tests/misc/src/test_ra8_ble.c; NimBLE host code is SOUP (see docs/SOUP/nimble.md).
States mirror the RA8D2 LPM modes: run -> sleep -> standby -> deep_standby -> software_standby. Wake events route through ra8_lpm.c. Test: tests/misc/src/test_ra8_power_profile.c.
States: armed -> petting -> overdue -> reset_pending. Each registered task posts a heartbeat; the supervisor refuses to refresh the IWDT if any task is overdue. Test: tests/hal/src/test_ra8_wdt_supervisor.c.
Every Ring 3 driver cites the HUM section it implements via an @cite HUM-Ch-NN doxygen tag, audited by scripts/checks/cite_check.py. Examples:
| Driver | Algorithm / sequence | HUM reference |
|---|---|---|
| ra8_cgc.c | PLL-from-MOSC bring-up sequence | HUM Ch 9 ("Clock Generation") |
| ra8_sdramc.c | SDRAM mode-register write + auto-refresh setup | HUM Ch 53 ("SDRAMC") |
| ra8_xspi.c | xSPI calibration + 8-line DDR mode select | HUM Ch 56 ("xSPI") |
| ra8_glcdc.c | Layer config + dot-clock divisor calculation | HUM Ch 60 ("GLCDC") |
| ra8_mipi_dsi.c | DSI link bring-up + low-power escape | HUM Ch 61 ("MIPI DSI") |
| ra8_etha.c | ETHA descriptor-ring init + frame TX/RX | HUM Ch 39 ("Ethernet Agent") |
| ra8_i3c_i2c.c | I2C controller-mode bit-timing | HUM Ch 36 ("IIC-B") |
| ra8_sci.c | UART baud-rate divisor selection | HUM Ch 35 ("SCI") |
| ra8_flash.c | MRAM erase + program (HP-flash semantics) | HUM Ch 50 ("Flash Memory") |
| ra8_iwdt.c | IWDT enable + refresh window | HUM Ch 32 ("IWDT") |
| ra8_lpm.c | LPM transition gating (sleep/standby/deep-standby) | HUM Ch 12 ("LPM") |
cite_check.py --strict enforces citation presence as a fail-closed gate.
Per ./PSAC.md Section 2.4 the crypto stack is Mbed TLS
| Use | PSA key type | Algorithm | Source |
|---|---|---|---|
| TLS handshake signing | PSA_KEY_TYPE_ECC_KEY_PAIR(SECP256R1) | PSA_ALG_ECDSA(PSA_ALG_SHA_256) | libs/ra8_tls/src/ra8_tls.c |
| OTA image authenticity | PSA_KEY_TYPE_ECC_PUBLIC_KEY(SECP256R1) | PSA_ALG_ECDSA(PSA_ALG_SHA_256) | libs/ra8_secure_app/src/ota_commit.c |
| Symmetric key wrap | PSA_KEY_TYPE_AES | PSA_ALG_GCM | libs/ra8_secure_app/src/key_import.c |
| Entropy | n/a | TRNG via secure_trng.c | libs/ra8_secure_app/src/secure_trng.c |
The RSIP HW path for key wrap is BLOCKED-VENDOR (REQ-DRV-061/062); the software fallback (RA8_RSIP_SOFTWARE_BACKEND) is emulator-only and SHALL NOT ship in a certified build (PSAC Section 7.2).
libs/ra8_fs/ is the first-party FAT12/16/32 + exFAT implementation (the vendored FileX was retired by #611); it mounts any block-device backend, including the EK-RA8D2 64 MiB Octo-SPI NOR through LevelX (NOR flash translation layer, SOUP per ../SOUP/levelx.md) via port/levelx/src/lx_fs_backend.c.
libs/ra8_net_pal/ is the first-party transport abstraction. Applications select NetX Duo or lwIP from the SOUP catalogue through the corresponding port layer; the retired separate first-party stack is no longer present.
Every cross-function error follows the pipeline:
The macro logs (level = error) via ra8_log_error and returns the unmodified err value. This implements REQ-CORE-003 / REQ-SAFE-007 (NASA P10 Rule 7 – check every return value).
Hard fault / bus fault / usage fault / mem-manage / secure fault all land in libs/ra8_core/src/ra8_exception.c, which captures the processor exception-stack frame, logs it through ra8_log_error, and hands off to ra8_error_handler.c. The latter is the single controlled-halt bottleneck (REQ-CORE-010) and is the only place that spins or resets after a fatal error.
ra8_wdt_supervisor (REQ-HAL-004) refuses to refresh the IWDT once any registered task heartbeat is overdue. The IWDT therefore expires and resets the chip rather than letting a wedged task hold the system indefinitely. Reset cause is preserved in the RSTSR registers and read back by ra8_reset.c (REQ-DRV-057) on the next boot.
A SecureFault SHALL trap to the per-app secure_exception.c (REQ-CHIP-003) which feeds the same ra8_error_handler bottleneck. This guarantees no S-side state is left in an indeterminate condition after an SAU violation.
Apps whose CMake declarations select USES threadx link ThreadX 6.5.0 from the SOUP catalogue (../SOUP/threadx.md). The ThreadX timer-tick is driven from the same SysTick that backs ra8_time so monotonic time is consistent in either bare-metal or RTOS builds.
Apps without ThreadX run a simple while(1) main loop with optional __WFI() between events; IRQs do all real work. The IWDT is refreshed from the main loop only after ra8_wdt_supervisor confirms heartbeats.
NVIC installation and priority validation are centralised in libs/ra8_hal/src/ra8_isr.c (REQ-DRV-040). The public contract and current typed bounds (k_ra8_isr_prio_max and k_ra8_isr_prio_default) are in libs/ra8_hal/inc/ra8_isr.h; drivers provide the priority when they call the installation API. A source-class priority allocation table has not yet been qualified and is therefore not claimed here.
| Module class | Re-entrant | Notes |
|---|---|---|
| ra8_log | Yes | Lock-free ring buffer with single-producer per priority. |
| ra8_time | Yes | SysTick read is a single 32-bit load. |
| ra8_pin_validator | No | Init-time only; caller must mask IRQs. |
| Driver _init functions | No | Init-time only; caller must mask IRQs. |
| Driver _read/_write | Per driver | Documented in each driver's @par Thread Safety. |
| NSC veneers | Yes | Re-entrant from NS; veneer body is short and copies its inputs to S stack. |
| ra8_error_handler | One-shot | First call wins; subsequent calls spin. |
Every REQ-XXX item in ./SRS.md maps to either a host test under ../../tests/ or a verification gap. The gap inventory is:
The SDD does not own gap closure; it owns the design choices that the gap-closure work is verifying.