|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
IT8951 e-paper full + partial refresh demo through the display PAL. More...
#include <stddef.h>#include <stdint.h>#include "ra8_board_ek_ra8d2.h"#include "ra8_boot_entry.h"#include "ra8_cgc.h"#include "ra8_display_pal.h"#include "ra8_display_pal_eink.h"#include "ra8_epaper.h"#include "ra8_epd_cal.h"#include "ra8_err.h"#include "ra8_io_spi_bus.h"#include "ra8_io_spi_bus_spi_b.h"#include "ra8_isr.h"#include "ra8_mstp.h"#include "ra8_panel.h"#include "ra8_port_constants.h"#include "ra8_port_utils.h"#include "ra8_spi.h"#include "ra8_time.h"Go to the source code of this file.
Enumerations | |
| enum | ep_geom_t : uint16_t { k_ep_panel_w = 128U , k_ep_panel_h = 128U , k_ep_cell = 16U } |
| Panel + framebuffer geometry. More... | |
| enum | ep_region_t : uint16_t { k_ep_box_x = 48U , k_ep_box_y = 48U , k_ep_box_w = 32U , k_ep_box_h = 32U } |
| Sub-rectangle updated by the partial refresh. More... | |
| enum | ep_color_t : uint16_t { k_ep_white = 0xFFFFU , k_ep_black = 0x0000U } |
| RGB565 shades used by the test pattern. More... | |
| enum | ep_bus_t : uint32_t { k_ep_spi_channel = 0U , k_ep_spi_baud_hz = 10000000U , k_ep_uart_baud = 115200U , k_ep_powerup_ms = 50U , k_ep_heartbeat_ms = 500U } |
| SPI + UART bring-up parameters. More... | |
| enum | ep_fmt_t : uint8_t { k_ep_line_max = 48U , k_ep_dec_digits = 10U , k_ep_radix = 10U , k_ep_cr = '\r' , k_ep_lf = '\n' } |
| UART line-formatting constants. More... | |
| enum | ep_pin_t : uint16_t { k_ep_reset_pin = ((ra8_port_pin_t)(((uint16_t)(k_ra8_port_4) << 8) | (uint16_t)(k_ra8_pin_0))) , k_ep_hrdy_pin = ((ra8_port_pin_t)(((uint16_t)(k_ra8_port_4) << 8) | (uint16_t)(k_ra8_pin_1))) } |
| IT8951 control GPIOs on the (hypothetical) e-paper carrier. More... | |
| enum | ep_vcom_limits_t : uint16_t { k_ep_vcom_min_mv = 200U , k_ep_vcom_max_mv = 4000U } |
| The plausible VCOM magnitude window for this panel family. More... | |
Functions | |
| static uint16_t | ep_checker_px (uint16_t x, uint16_t y) |
| Checkerboard colour for a framebuffer pixel. | |
| static bool | ep_region_fits (uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t pw, uint16_t ph) |
| Whether a rectangle (w, h >= 1) fits wholly inside the panel. | |
| static bool | ep_flush_ok (ra8_err_t init_err, ra8_err_t full_err, ra8_err_t part_err) |
| PASS verdict: every stage returned k_ra8_ok. | |
| static uint32_t | ep_u32_to_dec (uint8_t *buf, uint32_t val) |
| Write the decimal digits of val into buf; return the count. | |
| static void | ep_panic_halt (void) |
| Halt forever with the red board LED on. | |
| static void | ep_emit (const uint8_t *data, uint32_t len) |
| Emit a NUL-free byte span on the SCI console (best effort). | |
| static void | ep_bringup_core (uint32_t *out_pclka_hz) |
| Bring up clocks, MSTP, SysTick, the console and both LEDs. | |
| static void | ep_bringup_panel_bus (uint32_t pclka_hz) |
| Configure the panel GPIOs + SPI bus and fill s_epaper_cfg. | |
| static ra8_err_t | ep_vcom_get (void *ctx, uint16_t *out_mv) |
| ra8_epd_cal read seam bound to the IT8951 VCOM command. | |
| static ra8_err_t | ep_vcom_set (void *ctx, uint16_t mv) |
| ra8_epd_cal write seam bound to the IT8951 VCOM command. | |
| static bool | ep_calibrate_vcom (void) |
| Resolve this panel's VCOM and programme it, or refuse to draw. | |
| static void | ep_paint_checker (void) |
| Paint the whole framebuffer with the checkerboard pattern. | |
| static void | ep_paint_region_black (void) |
| Blacken the partial-refresh sub-rectangle in the framebuffer. | |
| static void | ep_report_stage (const char *label, uint32_t dt_ms, uint32_t pixels) |
| Print epaper: <label> ms=<dt> px=<count> on the console. | |
| static void | ep_report_init (void) |
| Print epaper: init ok panel=<w>x<h>. | |
| static void | ep_run_refresh_cycle (ra8_err_t *full_err, ra8_err_t *part_err) |
| Drive the full (checker/GC16) then partial (box/A2) refresh cycle. | |
| void | main (void) |
| Application entry: e-ink full + partial refresh through the PAL. | |
Variables | |
| static uint16_t | s_framebuffer [(uint32_t) k_ep_panel_w *(uint32_t) k_ep_panel_h] |
| RGB565 framebuffer in SRAM, 64-byte AXI-burst aligned. | |
| static ra8_io_spi_bus_t | s_spi_bus |
| ra8_io SPI-bus handle bound to SPI_B channel 0. | |
| static ra8_epaper_cfg_t | s_epaper_cfg |
| IT8951 descriptor handed to the e-ink backend via panel_timing. | |
| static display_handle_t * | s_display = nullptr |
| PAL handle returned by display_init. | |
| static display_caps_t | s_caps |
| Cached backend caps + framebuffer descriptor. | |
| static display_fb_t | s_fb |
| static const uint8_t | k_ep_msg_pass [] = "epaper: PASS\r\n" |
| PASS / FAIL banners. | |
| static const uint8_t | k_ep_msg_fail [] = "epaper: FAIL\r\n" |
| static const uint8_t | k_ep_msg_no_vcom [] = "epaper: NO TRUSTED VCOM -- panel left dark\r\n" |
| Banner for the INV-VCOM-1 refusal. | |
IT8951 e-paper full + partial refresh demo through the display PAL.
End-to-end example for the e-ink display path (#256): it drives an IT8951-compatible e-paper panel entirely through libs/ra8_display_pal's e-ink backend (k_display_backend_eink_it8951), which sits on the ra8_epaper HAL driver over an injected ra8_io_spi_bus seam. The app itself never names ra8_epaper_* – it paints a canonical RGB565 framebuffer and calls the same six PAL entry points the LCD demo uses.
Flow:
The EK-RA8D2 ships a parallel-RGB TFT, not e-paper, so on-panel HIL is pending an IT8951 carrier on the bench (see README). tools/ra8_emulator models the IT8951 as an SPI device (--eink): it answers HRDY, the GET_DEV_INFO drain and the LUTAFSR "LUT idle" poll, so this whole path runs headlessly to its epaper: PASS banner – EIL == HIL.
The reported refresh times are informational: on silicon a GC16 full refresh is hundreds of milliseconds and an A2 partial tens; under ra8_emulator the modelled controller completes instantly, so the numbers are near zero. The PASS verdict never depends on a timing value.
Definition in file main.c.
| enum ep_bus_t : uint32_t |
| enum ep_color_t : uint16_t |
| enum ep_fmt_t : uint8_t |
| enum ep_geom_t : uint16_t |
Panel + framebuffer geometry.
A modest 128 x 128 8bpp panel keeps the per-pixel SPI streaming fast under ra8_emulator while still exercising a full + partial refresh. RGB565 framebuffer = 128 * 128 * 2 = 32 KiB in SRAM.
| Enumerator | |
|---|---|
| k_ep_panel_w | Panel + framebuffer width (px). |
| k_ep_panel_h | Panel + framebuffer height (px). |
| k_ep_cell | Checkerboard cell size (px). |
| enum ep_pin_t : uint16_t |
IT8951 control GPIOs on the (hypothetical) e-paper carrier.
These are NOT stock EK-RA8D2 board facts – the EK ships a parallel TFT – so they live in the app, not the board layer. They match the pins the ra8_emulator IT8951 model drives (P4_00 /RESET, P4_01 HRDY). The SPI_B COPI/CIPO/SCK routing for the carrier is documented in the README; ra8_emulator does not require it.
| Enumerator | |
|---|---|
| k_ep_reset_pin | IT8951 /RESET (P4_00). |
| k_ep_hrdy_pin | IT8951 HRDY (P4_01). |
| enum ep_region_t : uint16_t |
| enum ep_vcom_limits_t : uint16_t |
The plausible VCOM magnitude window for this panel family.
A range, never a value: the range says "no sane panel is calibrated outside this", which is enough to reject a controller reporting 0 or 0xFFFF, while carrying none of the per-unit information that makes a hardcoded VCOM damaging. Panels in this family ship labelled around -1.5 V; the window is deliberately wider than that so a legitimately unusual panel is not locked out.
| Enumerator | |
|---|---|
| k_ep_vcom_min_mv | Lowest plausible magnitude, millivolts. |
| k_ep_vcom_max_mv | Highest plausible magnitude, millivolts. |
|
static |
Bring up clocks, MSTP, SysTick, the console and both LEDs.
| [out] | out_pclka_hz | Receives PCLKA in Hz (SPI clock source). |
Definition at line 429 of file main.c.
References ep_panic_halt(), k_ep_uart_baud, k_ra8_board_led_blue, k_ra8_board_led_red, k_ra8_clock_id_cpuclk0, k_ra8_clock_id_pclka, k_ra8_ok, ra8_board_led_init(), ra8_board_uart_console_init(), ra8_cgc_get_clock_hz(), ra8_cgc_init(), ra8_mstp_init(), and ra8_time_init().
Referenced by main().
|
static |
Configure the panel GPIOs + SPI bus and fill s_epaper_cfg.
Drives /RESET high (output), configures HRDY as a pulled-up input, brings up SPI_B channel 0 in mode 0 as controller, binds it into an ra8_io_spi_bus and exposes it through the Ring-3 seam the IT8951 descriptor carries.
| [in] | pclka_hz | PCLKA in Hz (SPI clock source). |
Definition at line 477 of file main.c.
References ep_panic_halt(), k_ep_hrdy_pin, k_ep_panel_h, k_ep_panel_w, k_ep_reset_pin, k_ep_spi_baud_hz, k_ep_spi_channel, k_ra8_level_high, k_ra8_ok, k_ra8_pull_up, k_ra8_spi_mode_0, ra8_epaper_waveform_cfg_for_lut(), ra8_gpio_input_init(), ra8_gpio_output_init(), ra8_io_spi_bus_as_ops(), ra8_io_spi_bus_bind_spi_b(), ra8_spi_init(), s_epaper_cfg, and s_spi_bus.
Referenced by main().
|
static |
Resolve this panel's VCOM and programme it, or refuse to draw.
The INV-VCOM-1 gate, and the reason this app cannot simply start flushing after display_init. ra8_epd_cal_resolve walks the controller's own persisted value, then the per-device record, then an operator-supplied value, and fails rather than inventing one; ra8_epd_cal_apply programmes the winner and confirms it by readback. Only then does the driver permit a refresh at all.
The store seams are left unbound on purpose. Reading the per-device record needs a fault-tolerant extra-MRAM probe (a virgin page bus-faults on the first read), which today exists only inside the DFU anti-rollback module and has not been lifted into a shared helper. TODO(shared fault-tolerant extra-MRAM probe helper + per-device config record reader): bind store.read / store.write once that lands, at which point a provisioned unit resolves from its own record instead of trusting whatever the controller board happens to hold.
Until then this app resolves from the controller's persisted value, which is what makes a vendor-provisioned driver board work out of the box, and refuses to drive anything that cannot supply one.
| true | Refresh is permitted. |
| false | No trusted VCOM; the caller must leave the panel dark. |
Definition at line 612 of file main.c.
References ep_vcom_get(), ep_vcom_set(), k_ep_vcom_max_mv, k_ep_vcom_min_mv, k_ra8_ok, ra8_epd_cal_apply(), and ra8_epd_cal_resolve().
Referenced by main().
|
static |
Checkerboard colour for a framebuffer pixel.
black when ((x/cell) + (y/cell)) is odd, else white – a classic e-ink alignment pattern.
| [in] | x | Column (0 .. k_ep_panel_w-1). |
| [in] | y | Row (0 .. k_ep_panel_h-1). |
| k_ep_black | Odd cell. |
| k_ep_white | Even cell. |
Definition at line 273 of file main.c.
References k_ep_black, k_ep_cell, and k_ep_white.
Referenced by ep_paint_checker().
|
static |
Emit a NUL-free byte span on the SCI console (best effort).
| [in] | data | Bytes to write. |
| [in] | len | Byte count. |
Definition at line 411 of file main.c.
References ra8_board_uart_console_write().
Referenced by ep_report_init(), ep_report_stage(), and main().
PASS verdict: every stage returned k_ra8_ok.
| [in] | init_err | display_init result. |
| [in] | full_err | full-refresh display_flush result. |
| [in] | part_err | partial-refresh display_flush result. |
| true | All three are k_ra8_ok. |
| false | Any stage failed. |
Definition at line 332 of file main.c.
References k_ra8_ok.
Referenced by main().
|
static |
Paint the whole framebuffer with the checkerboard pattern.
Definition at line 640 of file main.c.
References ep_checker_px(), and s_fb.
Referenced by ep_run_refresh_cycle().
|
static |
Blacken the partial-refresh sub-rectangle in the framebuffer.
Definition at line 662 of file main.c.
References k_ep_black, k_ep_box_h, k_ep_box_w, k_ep_box_x, k_ep_box_y, and s_fb.
Referenced by ep_run_refresh_cycle().
|
static |
Halt forever with the red board LED on.
Definition at line 389 of file main.c.
References k_ra8_board_led_red, and ra8_board_led_on().
Referenced by ep_bringup_core(), ep_bringup_panel_bus(), ep_parse_or_halt(), ep_setup_or_halt(), and main().
|
static |
Whether a rectangle (w, h >= 1) fits wholly inside the panel.
Compound bounds guard used before the partial flush so a bad region is rejected rather than clipped. The right / bottom edge checks subsume the left / top ones for a non-empty rectangle, so the decision is the two INDEPENDENT edge tests – one on the x axis, one on the y axis.
| [in] | x | Rectangle left edge. |
| [in] | y | Rectangle top edge. |
| [in] | w | Rectangle width (>= 1). |
| [in] | h | Rectangle height (>= 1). |
| [in] | pw | Panel width. |
| [in] | ph | Panel height. |
| true | Both the right and bottom edges are in range. |
| false | Either edge steps out of bounds. |
Definition at line 308 of file main.c.
Referenced by ep_run_refresh_cycle().
|
static |
Print epaper: init ok panel=<w>x<h>.
Definition at line 727 of file main.c.
References ep_emit(), ep_u32_to_dec(), k_ep_cr, k_ep_lf, k_ep_line_max, k_ep_panel_h, and k_ep_panel_w.
Referenced by main().
|
static |
Print epaper: <label> ms=<dt> px=<count> on the console.
| [in] | label | NUL-terminated stage label (e.g. "full-refresh"). |
| [in] | dt_ms | Measured flush time in milliseconds. |
| [in] | pixels | Pixels refreshed this stage. |
Definition at line 690 of file main.c.
References ep_emit(), ep_u32_to_dec(), k_ep_cr, k_ep_lf, and k_ep_line_max.
Referenced by ep_run_refresh_cycle().
Drive the full (checker/GC16) then partial (box/A2) refresh cycle.
Repaints the framebuffer and flushes it twice through the display PAL: a full-panel quality refresh, then a bounds-checked partial fast refresh of the demo box. Each stage's flush time and pixel count are reported. The partial stage is skipped – leaving part_err at k_ra8_err_invalid_arg – when the box does not fit the panel.
| [out] | full_err | Receives the full-refresh flush result. |
| [out] | part_err | Receives the partial-refresh flush result, or k_ra8_err_invalid_arg when the box was out of bounds. |
Definition at line 765 of file main.c.
References display_flush(), display_full_rect(), ep_paint_checker(), ep_paint_region_black(), ep_region_fits(), ep_report_stage(), k_display_refresh_fast, k_display_refresh_quality, k_ep_box_h, k_ep_box_w, k_ep_box_x, k_ep_box_y, k_ep_panel_h, k_ep_panel_w, k_ra8_err_invalid_arg, ra8_now_ms(), and s_display.
Referenced by main().
|
static |
Write the decimal digits of val into buf; return the count.
| [out] | buf | Destination (>= k_ep_dec_digits bytes). |
| [in] | val | Value to render. |
| 1 | For val == 0. |
Definition at line 354 of file main.c.
References k_ep_dec_digits, and k_ep_radix.
Referenced by ep_report_init(), and ep_report_stage().
|
static |
ra8_epd_cal read seam bound to the IT8951 VCOM command.
Adapts the driver's context-free signature onto the seam's (ctx, out) shape. ctx is unused: the driver keeps one panel per build.
| [in] | ctx | Unused seam context. |
| [out] | out_mv | Receives the controller's VCOM magnitude; non-NULL. |
| k_ra8_ok | Controller answered. |
| k_ra8_err_null_ptr | out_mv is NULL. |
Definition at line 541 of file main.c.
References ra8_epaper_get_vcom().
Referenced by ep_calibrate_vcom().
|
static |
ra8_epd_cal write seam bound to the IT8951 VCOM command.
The driver's ra8_epaper_set_vcom verifies its own write by reading it back, so a k_ra8_ok from here means the controller confirmed the value – not merely that bytes were clocked out.
| [in] | ctx | Unused seam context. |
| [in] | mv | VCOM magnitude to programme, millivolts. |
| k_ra8_ok | Programmed and verified. |
| k_ra8_err_validation_failed | Readback disagreed. |
Definition at line 570 of file main.c.
References ra8_epaper_set_vcom().
Referenced by ep_calibrate_vcom().
| void main | ( | void | ) |
Application entry: e-ink full + partial refresh through the PAL.
The application entry point Reset_Handler hands control to.
Definition at line 809 of file main.c.
References display_deinit(), display_get_caps(), display_get_framebuffer(), display_init(), ep_bringup_core(), ep_bringup_panel_bus(), ep_calibrate_vcom(), ep_emit(), ep_flush_ok(), ep_panic_halt(), ep_report_init(), ep_run_refresh_cycle(), k_display_backend_eink_it8951, k_display_pixfmt_rgb565, k_ep_heartbeat_ms, k_ep_msg_fail, k_ep_msg_no_vcom, k_ep_msg_pass, k_ep_panel_h, k_ep_panel_w, k_ep_powerup_ms, k_ra8_board_led_blue, k_ra8_err_invalid_arg, k_ra8_ok, ra8_board_led_toggle(), ra8_delay_ms(), ra8_isr_globals_enable(), s_caps, s_display, s_epaper_cfg, s_fb, and s_framebuffer.
|
static |
|
static |
Banner for the INV-VCOM-1 refusal.
Deliberately distinct from the generic FAIL banner: "this panel has no trusted calibration" is a different fault from "the SPI bring-up broke", and the operator's next action differs (read the number off the flex cable and provision it, versus check the wiring).
Definition at line 222 of file main.c.
Referenced by main().
|
static |
|
static |
Cached backend caps + framebuffer descriptor.
Definition at line 202 of file main.c.
Referenced by app_bringup_display(), and main().
|
static |
PAL handle returned by display_init.
|
static |
IT8951 descriptor handed to the e-ink backend via panel_timing.
Filled in ep_bringup_panel_bus; carries the injected SPI seam, the reset / busy GPIOs and the native panel size.
Definition at line 196 of file main.c.
Referenced by ep_bringup_panel_bus(), and main().
|
static |
Definition at line 203 of file main.c.
Referenced by app_bringup_display(), app_bringup_gfx(), app_bringup_panel(), app_paint_bars(), cm_bringup_panel(), ep_paint_checker(), ep_paint_region_black(), er_draw_reading_body_reflow(), er_flush_event(), er_handle_reading_tap(), er_kbd_keys_render(), er_lib_body_render(), er_lib_sb_render(), er_nag_hit(), er_nag_render(), er_read_body_render(), er_read_footer_render(), er_read_sb_render(), er_render_keyboard(), er_render_library(), er_render_nag_region(), er_render_reading(), ez_bringup_panel(), main(), mg_bringup_panel(), and sfr_bringup_panel().
|
static |
|
static |
ra8_io SPI-bus handle bound to SPI_B channel 0.
Out-lives every ra8_epaper call: the epaper bus seam's ctx points at this handle.
Definition at line 184 of file main.c.
Referenced by ep_bringup_panel_bus().