ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_epaper_geom.c File Reference

IT8951 geometry, pixel-format, waveform-map and config validation. More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_epaper.h"
#include "ra8_err.h"
Include dependency graph for ra8_epaper_geom.c:

Go to the source code of this file.

Enumerations

enum  ra8_epaper_geom_const_t : uint16_t {
  k_ra8_epaper_geom_bits_per_byte = 8U ,
  k_ra8_epaper_geom_panel_max_dim = 4096U
}
 Packing arithmetic constants (no magic numbers). More...
enum  ra8_epaper_bpp_t : uint8_t {
  k_ra8_epaper_bpp_1 = 1U ,
  k_ra8_epaper_bpp_2 = 2U ,
  k_ra8_epaper_bpp_4 = 4U ,
  k_ra8_epaper_bpp_8 = 8U
}
 Bit depth of each ra8_epaper_pixel_format_t. More...
enum  ra8_epaper_lut_mode_t : uint8_t {
  k_ra8_epaper_lut_init = 0U ,
  k_ra8_epaper_lut_du = 1U ,
  k_ra8_epaper_lut_gc16 = 2U ,
  k_ra8_epaper_lut_a2_m641 = 4U ,
  k_ra8_epaper_lut_a2_gen = 6U
}
 Waveform LUT mode numbers the vendor documents. More...

Functions

uint8_t ra8_epaper_bits_per_pixel (ra8_epaper_pixel_format_t pf)
 Bits per pixel carried by a ra8_epaper_pixel_format_t.
ra8_err_t ra8_epaper_image_bytes (const ra8_epaper_area_t *area, ra8_epaper_pixel_format_t pf, size_t *out_bytes)
 Bytes a packed source buffer needs for area at depth pf.
bool ra8_epaper_area_is_aligned (const ra8_epaper_area_t *area, ra8_epaper_pixel_format_t pf)
 Report whether area satisfies the depth's X/width alignment.
ra8_err_t ra8_epaper_align_area (ra8_epaper_area_t *area, ra8_epaper_pixel_format_t pf, uint16_t panel_width)
 Grow area outward onto the alignment grid its depth requires.
ra8_err_t ra8_epaper_waveform_cfg_for_lut (const char *lut_version, ra8_epaper_waveform_cfg_t *out_cfg)
 Fill a waveform map from a controller-reported LUT version.
static ra8_err_t internal_ra8_epaper_validate_waveform (const ra8_epaper_waveform_cfg_t *wf)
 Validate the caller's waveform map against the LUT mode range.
ra8_err_t ra8_epaper_validate_cfg (const ra8_epaper_cfg_t *cfg)
 Validate a panel descriptor without touching any hardware.
bool ra8_epaper_geometry_agrees (const ra8_epaper_dev_info_t *info, const ra8_epaper_cfg_t *cfg)
 Report whether reported panel geometry matches the descriptor.

Variables

static const char *const s_tag = "EPAPER"
 Logging tag used by the null-argument guards in this TU.
static const char *const s_lut_m641 = "M641"
 LUT-version token identifying the 6 inch / 6 inch HD waveform set.

Detailed Description

IT8951 geometry, pixel-format, waveform-map and config validation.

Tag
[Ring 3 / HAL] {World: NS}

The pure half of the IT8951 driver, split out of ra8_epaper.c so neither translation unit exceeds the repository's file-size cap. These functions touch no bus, no GPIO and no driver state – they are total functions over their arguments, which is why they can be called (and tested) before ra8_epaper_init has ever run.

Three IT8951 facts are encoded here, and each one is a defect the driver previously had:

  • Pixel depth is not the wire code. The controller numbers its LD_IMG_AREA formats 2 bpp = 0, 3 bpp = 1, 4 bpp = 2, 8 bpp = 3. ra8_epaper_bits_per_pixel and ra8_epaper_image_bytes deal in real bit depths; the wire code is applied inside ra8_epaper.c.
  • 1 bpp updates must sit on a 32-pixel grid. The bi-level LUT reads the update window in 4-byte units, so a misaligned A2 update renders nothing at all – the controller accepts the command and the screen stays blank. ra8_epaper_area_is_aligned detects that and ra8_epaper_align_area repairs it by growing outward.
  • Waveform mode numbers are per-panel. They come from the controller's firmware LUT, not from the driver; ra8_epaper_waveform_cfg_for_lut derives them from the reported LUT version string.

ra8_epaper_validate_cfg lives here for the same reason: it is a total function over a descriptor, checking exactly the geometry and waveform-map facts above, so it can reject a bad board descriptor before any bus exists to talk to.

Definition in file ra8_epaper_geom.c.

Enumeration Type Documentation

◆ ra8_epaper_bpp_t

enum ra8_epaper_bpp_t : uint8_t

Bit depth of each ra8_epaper_pixel_format_t.

Enumerator
k_ra8_epaper_bpp_1 

k_ra8_epaper_pf_1bpp.

k_ra8_epaper_bpp_2 

k_ra8_epaper_pf_2bpp.

k_ra8_epaper_bpp_4 

k_ra8_epaper_pf_4bpp.

k_ra8_epaper_bpp_8 

k_ra8_epaper_pf_8bpp.

Definition at line 68 of file ra8_epaper_geom.c.

◆ ra8_epaper_geom_const_t

enum ra8_epaper_geom_const_t : uint16_t

Packing arithmetic constants (no magic numbers).

Enumerator
k_ra8_epaper_geom_bits_per_byte 

Row-packing denominator.

k_ra8_epaper_geom_panel_max_dim 

Sanity ceiling on cfg dims.

Definition at line 59 of file ra8_epaper_geom.c.

◆ ra8_epaper_lut_mode_t

enum ra8_epaper_lut_mode_t : uint8_t

Waveform LUT mode numbers the vendor documents.

INIT / DU / GC16 are stable across every Waveshare IT8951 panel. A2 is the one that moves: mode 4 on the M641 LUT (6 inch, 6 inch HD) and mode 6 on the vendor's generic default for the larger panels.

Enumerator
k_ra8_epaper_lut_init 

INIT on every documented LUT.

k_ra8_epaper_lut_du 

DU on every documented LUT.

k_ra8_epaper_lut_gc16 

GC16 on every documented LUT.

k_ra8_epaper_lut_a2_m641 

A2 on the M641 LUT.

k_ra8_epaper_lut_a2_gen 

A2 on the vendor generic LUT.

Definition at line 84 of file ra8_epaper_geom.c.

Function Documentation

◆ internal_ra8_epaper_validate_waveform()

ra8_err_t internal_ra8_epaper_validate_waveform ( const ra8_epaper_waveform_cfg_t * wf)
staticnodiscard

Validate the caller's waveform map against the LUT mode range.

A zero-initialised map would silently refresh every mode as INIT, so DU / GC16 / A2 are additionally required to be non-zero. That single rule is what stops a board descriptor inheriting another panel's numbering by omission.

Parameters
[in]wfCaller-supplied waveform map; non-NULL.
Returns
k_ra8_ok when usable, k_ra8_err_invalid_arg otherwise.
Precondition
wf is non-NULL (the caller checked).
wf is fully initialised by the caller.
Postcondition
No state is mutated.
On success every mode is non-zero except init.
Note
Thread-safe: pure function over its argument.
Since
0.1.0

Definition at line 225 of file ra8_epaper_geom.c.

References ra8_epaper_waveform_cfg_t::a2, ra8_epaper_waveform_cfg_t::du, ra8_epaper_waveform_cfg_t::gc16, ra8_epaper_waveform_cfg_t::init, k_ra8_epaper_wf_mode_max, k_ra8_err_invalid_arg, and k_ra8_ok.

Referenced by ra8_epaper_validate_cfg().

◆ ra8_epaper_align_area()

ra8_err_t ra8_epaper_align_area ( ra8_epaper_area_t * area,
ra8_epaper_pixel_format_t pf,
uint16_t panel_width )
nodiscard

Grow area outward onto the alignment grid its depth requires.

Rounds x down and the right edge up to the next multiple of k_ra8_epaper_align_1bpp_px, then clamps the right edge to panel_width. Growing outward (never inward) guarantees the caller's requested rectangle stays wholly covered, so the refresh is a superset of what was asked for rather than a silently cropped subset. A no-op for depths other than 1 bpp.

Parameters
[in,out]areaRectangle to align in place; non-NULL.
[in]pfPixel depth the rectangle will be sent at.
[in]panel_widthPanel width in pixels used as the clamp; must be non-zero and itself a multiple of k_ra8_epaper_align_1bpp_px when pf is 1 bpp, otherwise the clamp could reintroduce a misaligned right edge.
Returns
ra8_err_t error code.
Return values
k_ra8_ok*area is aligned and within the panel.
k_ra8_err_null_ptrarea is NULL.
k_ra8_err_invalid_argpanel_width is zero, area steps outside it, or the clamp cannot produce an aligned width.
Precondition
area lies within panel_width.
panel_width is the panel's true width.
Postcondition
On success ra8_epaper_area_is_aligned(area, pf) is true.
On success the output rectangle contains the input rectangle.
Note
Not thread-safe with respect to *area; the caller owns it.
Example:
ra8_epaper_area_t a = {.x = 17U, .y = 0U, .width = 3U, .height = 8U};
// a.x == 0, a.width == 32
ra8_err_t ra8_epaper_align_area(ra8_epaper_area_t *area, ra8_epaper_pixel_format_t pf, uint16_t panel_width)
Grow area outward onto the alignment grid its depth requires.
@ k_ra8_epaper_pf_1bpp
1 bpp bi-level, 8 px per byte (A2).
Definition ra8_epaper.h:181
Rectangle descriptor (top-left + size) used by load + display.
Definition ra8_epaper.h:317
See also
ra8_epaper_area_is_aligned
Since
0.1.0

Definition at line 152 of file ra8_epaper_geom.c.

References k_ra8_epaper_align_1bpp_px, k_ra8_epaper_pf_1bpp, k_ra8_err_invalid_arg, k_ra8_ok, RA8_CHECK_NULL_PTR, s_tag, ra8_epaper_area_t::width, and ra8_epaper_area_t::x.

◆ ra8_epaper_area_is_aligned()

bool ra8_epaper_area_is_aligned ( const ra8_epaper_area_t * area,
ra8_epaper_pixel_format_t pf )
nodiscard

Report whether area satisfies the depth's X/width alignment.

Only 1 bpp constrains geometry: the controller's bi-level LUT reads the update window in 4-byte units, so x and width must both be multiples of k_ra8_epaper_align_1bpp_px (32 pixels). Every other depth is unconstrained and always reports aligned.

Parameters
[in]areaRectangle to test; non-NULL.
[in]pfPixel depth the rectangle will be transferred at.
Returns
Whether the rectangle may be transferred as-is.
Return values
truepf is not 1 bpp, or both x and width sit on the 32-pixel grid.
falsepf is 1 bpp and x or width is misaligned.
Precondition
area is non-NULL and readable.
pf is a valid ra8_epaper_pixel_format_t.
Postcondition
No state mutated.
Return depends solely on the arguments.
Note
Pure function; thread-safe. A NULL area reports false rather than trapping, so callers can use this as a guard.
See also
ra8_epaper_align_area
Since
0.1.0

Definition at line 138 of file ra8_epaper_geom.c.

References k_ra8_epaper_align_1bpp_px, k_ra8_epaper_pf_1bpp, ra8_epaper_area_t::width, and ra8_epaper_area_t::x.

Referenced by internal_ra8_epaper_validate_load().

◆ ra8_epaper_bits_per_pixel()

uint8_t ra8_epaper_bits_per_pixel ( ra8_epaper_pixel_format_t pf)
nodiscard

Bits per pixel carried by a ra8_epaper_pixel_format_t.

Pure lookup used to size transfers. Kept public because the PAL and the host tests both need the packing arithmetic to agree with the driver's.

Parameters
[in]pfPixel format selector.
Returns
The number of bits each pixel occupies in the source buffer.
Return values
1For k_ra8_epaper_pf_1bpp.
2For k_ra8_epaper_pf_2bpp.
4For k_ra8_epaper_pf_4bpp.
8For k_ra8_epaper_pf_8bpp and any out-of-range input (8 bpp is the widest format, so an unknown selector can only over-estimate the buffer a caller must supply – it can never under-run one).
Precondition
None.
None.
Postcondition
No state mutated.
Return depends solely on pf.
Note
Pure function; thread-safe.
See also
ra8_epaper_image_bytes
Since
0.1.0

Definition at line 106 of file ra8_epaper_geom.c.

References k_ra8_epaper_bpp_1, k_ra8_epaper_bpp_2, k_ra8_epaper_bpp_4, k_ra8_epaper_bpp_8, k_ra8_epaper_pf_1bpp, k_ra8_epaper_pf_2bpp, k_ra8_epaper_pf_4bpp, and k_ra8_epaper_pf_8bpp.

Referenced by ra8_epaper_image_bytes().

◆ ra8_epaper_geometry_agrees()

bool ra8_epaper_geometry_agrees ( const ra8_epaper_dev_info_t * info,
const ra8_epaper_cfg_t * cfg )
nodiscard

Report whether reported panel geometry matches the descriptor.

ra8_epaper_init cross-checks the geometry the controller reports in its GET_DEV_INFO block against the descriptor it was handed, and warns rather than fails on a mismatch. Both halves of that are deliberate: a controller that has not finished loading its waveform answers the first read with zeroes, and an application may legitimately drive a sub-window of a larger panel, so a mismatch is information rather than an error.

Split out of ra8_epaper_init so the comparison is a pure function that host tests can vary directly. Inside init it could only be reached through a real GET_DEV_INFO exchange, whose reported dimensions the test bus cannot steer to a value that is also a legal descriptor size – which left the "agrees" case untestable.

Parameters
[in]infoDecoded device block; NULL is treated as disagreement.
[in]cfgDescriptor to compare against; NULL likewise.
Returns
true when both dimensions match, false otherwise.
Precondition
info was populated by ra8_epaper_decode_dev_info.
cfg is the descriptor passed to ra8_epaper_init.
Postcondition
No state is mutated and no bus traffic is issued.
A NULL argument yields false rather than a fault.
Note
Thread-safe: pure function over its arguments.
See also
ra8_epaper_init
ra8_epaper_decode_dev_info
Since
0.1.0

Definition at line 250 of file ra8_epaper_geom.c.

References ra8_epaper_cfg_t::panel_height, ra8_epaper_dev_info_t::panel_height, ra8_epaper_cfg_t::panel_width, and ra8_epaper_dev_info_t::panel_width.

Referenced by ra8_epaper_init().

◆ ra8_epaper_image_bytes()

ra8_err_t ra8_epaper_image_bytes ( const ra8_epaper_area_t * area,
ra8_epaper_pixel_format_t pf,
size_t * out_bytes )
nodiscard

Bytes a packed source buffer needs for area at depth pf.

Rows are packed independently and each starts on a byte boundary, so the size is ceil(width * bpp / 8) * height. This is the exact value ra8_epaper_load_image requires in buf_len.

Parameters
[in]areaRectangle to be transferred; non-NULL.
[in]pfSource pixel depth.
[out]out_bytesReceives the required byte count; non-NULL.
Returns
ra8_err_t error code.
Return values
k_ra8_ok*out_bytes holds the size.
k_ra8_err_null_ptrarea or out_bytes is NULL.
k_ra8_err_invalid_sizearea has a zero dimension.
Precondition
area and out_bytes are readable / writable.
area describes a non-degenerate rectangle.
Postcondition
On success *out_bytes is non-zero.
On failure *out_bytes is untouched.
Note
Pure apart from the output write; thread-safe.
See also
ra8_epaper_bits_per_pixel
ra8_epaper_load_image
Since
0.1.0

Definition at line 121 of file ra8_epaper_geom.c.

References ra8_epaper_area_t::height, k_ra8_epaper_geom_bits_per_byte, k_ra8_err_invalid_size, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_epaper_bits_per_pixel(), s_tag, and ra8_epaper_area_t::width.

Referenced by internal_eink_load_rect(), and internal_ra8_epaper_validate_load().

◆ ra8_epaper_validate_cfg()

ra8_err_t ra8_epaper_validate_cfg ( const ra8_epaper_cfg_t * cfg)
nodiscard

Validate a panel descriptor without touching any hardware.

ra8_epaper_init calls this before it drives a single pin, so a bad descriptor is rejected with no bus traffic and no reset pulse. It is public because it is a total function over the descriptor: a board bring-up can check its own ra8_epaper_cfg_t before a controller is even attached.

Beyond range-checking the geometry, this rejects a zero-initialised waveform map. That check is load-bearing: mode 0 is INIT on every documented LUT, so a descriptor that forgot to fill the map would refresh every mode as a full INIT flash rather than fail, and a missing A2 would look like a merely slow panel instead of a misconfigured one.

Parameters
[in]cfgDescriptor to check; non-NULL.
Returns
ra8_err_t error code.
Return values
k_ra8_okEvery field is in range and usable.
k_ra8_err_null_ptrcfg is NULL.
k_ra8_err_invalid_argA field is out of range, the bus seam is unbound, or the waveform map is unset.
Precondition
cfg is fully initialised by the caller.
cfg->waveform names this panel's LUT mode numbers.
Postcondition
No hardware is touched and no driver state is mutated.
On k_ra8_ok the descriptor is safe to pass to ra8_epaper_init.
Note
Thread-safe: pure function over its argument.
See also
ra8_epaper_init
ra8_epaper_waveform_cfg_for_lut
Since
0.1.0

Definition at line 239 of file ra8_epaper_geom.c.

References ra8_epaper_cfg_t::bus, internal_ra8_epaper_validate_waveform(), k_ra8_epaper_geom_panel_max_dim, k_ra8_err_invalid_arg, ra8_epaper_cfg_t::panel_height, ra8_epaper_cfg_t::panel_width, RA8_CHECK_NULL_PTR, s_tag, ra8_epaper_cfg_t::waveform, and ra8_spi_bus_ops_t::xfer8.

Referenced by ra8_epaper_init().

◆ ra8_epaper_waveform_cfg_for_lut()

ra8_err_t ra8_epaper_waveform_cfg_for_lut ( const char * lut_version,
ra8_epaper_waveform_cfg_t * out_cfg )
nodiscard

Fill a waveform map from a controller-reported LUT version.

The waveform mode numbering is a property of the firmware LUT the IT8951 loaded, which GET_DEV_INFO reports as a version string. The M641 LUT – the 6 inch and 6 inch HD panels, including the Waveshare 1448x1072 HAT – places A2 at mode 4; the vendor's generic default for the larger 7.8 / 9.7 / 10.3 inch panels is mode 6. INIT (0), DU (1) and GC16 (2) are stable across both.

The match is a prefix match on the leading M641 token, because the reported string carries a build suffix that varies between controller firmware revisions.

Parameters
[in]lut_versionNUL-terminated LUT version string as reported in ra8_epaper_dev_info_t; non-NULL.
[out]out_cfgReceives the waveform map; non-NULL.
Returns
ra8_err_t error code.
Return values
k_ra8_ok*out_cfg populated (M641 or generic).
k_ra8_err_null_ptrlut_version or out_cfg is NULL.
Precondition
lut_version is NUL-terminated.
out_cfg is writable.
Postcondition
On success every member of *out_cfg is <= k_ra8_epaper_wf_mode_max.
On failure *out_cfg is untouched.
Note
Pure apart from the output write; thread-safe.
Warning
The generic fallback is the vendor's documented default, not a guess – but it has only been verified against the panels Waveshare documents. A panel whose LUT is neither M641 nor the generic numbering must state its map in the BSP descriptor.
See also
ra8_epaper_dev_info
ra8_epaper_waveform_cfg_t
Since
0.1.0

Definition at line 182 of file ra8_epaper_geom.c.

References ra8_epaper_waveform_cfg_t::a2, ra8_epaper_waveform_cfg_t::du, ra8_epaper_waveform_cfg_t::gc16, ra8_epaper_waveform_cfg_t::init, k_ra8_epaper_lut_a2_gen, k_ra8_epaper_lut_a2_m641, k_ra8_epaper_lut_du, k_ra8_epaper_lut_gc16, k_ra8_epaper_lut_init, k_ra8_ok, RA8_CHECK_NULL_PTR, s_lut_m641, and s_tag.

Referenced by ep_bringup_panel_bus().

Variable Documentation

◆ s_lut_m641

const char* const s_lut_m641 = "M641"
static

LUT-version token identifying the 6 inch / 6 inch HD waveform set.

Matched as a prefix because the controller appends a build suffix that varies between firmware revisions.

Note
Read-only; compared against the reported LUT version.
Warning
Changing this silently repoints A2 at a different LUT mode.
Since
0.1.0

Definition at line 104 of file ra8_epaper_geom.c.

Referenced by ra8_epaper_waveform_cfg_for_lut().

◆ s_tag

const char* const s_tag = "EPAPER"
static

Logging tag used by the null-argument guards in this TU.

Definition at line 53 of file ra8_epaper_geom.c.