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

IT8951 e-paper controller SPI driver – public API. More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_err.h"
#include "ra8_spi_bus_ops.h"
Include dependency graph for ra8_epaper.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ra8_epaper_waveform_cfg_t
 Per-panel map from ra8_epaper_waveform_t onto LUT mode numbers. More...
struct  ra8_epaper_dev_info_t
 Decoded GET_DEV_INFO (0x0302) response. More...
struct  ra8_epaper_cfg_t
 Configuration descriptor for ra8_epaper_init. More...
struct  ra8_epaper_area_t
 Rectangle descriptor (top-left + size) used by load + display. More...

Enumerations

enum  ra8_epaper_waveform_t : uint8_t {
  k_ra8_epaper_wf_init = 0U ,
  k_ra8_epaper_wf_du = 1U ,
  k_ra8_epaper_wf_gc16 = 2U ,
  k_ra8_epaper_wf_a2 = 3U
}
 Symbolic IT8951 panel-refresh waveform selectors. More...
enum  ra8_epaper_pixel_format_t : uint8_t {
  k_ra8_epaper_pf_1bpp = 0U ,
  k_ra8_epaper_pf_2bpp = 1U ,
  k_ra8_epaper_pf_4bpp = 2U ,
  k_ra8_epaper_pf_8bpp = 3U
}
 Source pixel depth for a ra8_epaper_load_image transfer. More...
enum  ra8_epaper_geom_limits_t : uint16_t {
  k_ra8_epaper_align_1bpp_px = 32U ,
  k_ra8_epaper_wf_mode_max = 7U
}
 Geometry / waveform constants the driver enforces. More...
enum  ra8_epaper_dev_info_limits_t : uint8_t { k_ra8_epaper_ver_chars = 16U }
 Sizing of the GET_DEV_INFO (0x0302) response block. More...
enum  ra8_epaper_endian_t : uint8_t {
  k_ra8_epaper_endian_little = 0U ,
  k_ra8_epaper_endian_big = 1U
}
 Source-buffer endianness flag for the LD_IMG_AREA transfer. More...

Functions

ra8_err_t ra8_epaper_init (const ra8_epaper_cfg_t *cfg)
 Bring up the IT8951 panel against the injected SPI bus seam.
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.
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.
ra8_err_t ra8_epaper_dev_info (ra8_epaper_dev_info_t *out_info)
 Hand back the GET_DEV_INFO block captured during init.
ra8_err_t ra8_epaper_decode_dev_info (const uint16_t *words, size_t count, ra8_epaper_dev_info_t *out_info)
 Decode a raw GET_DEV_INFO word block into a device-info struct.
ra8_err_t ra8_epaper_get_vcom (uint16_t *out_mv)
 Read the controller's current VCOM setting, in millivolts.
ra8_err_t ra8_epaper_set_vcom (uint16_t mv)
 Programme the controller's VCOM, verify it, and grant the INV-VCOM-1 permit.
bool ra8_epaper_vcom_verified (void)
 Report whether the INV-VCOM-1 permit is currently held.
ra8_err_t ra8_epaper_load_image (const ra8_epaper_area_t *area, const uint8_t *buf, size_t buf_len, ra8_epaper_pixel_format_t pf, ra8_epaper_endian_t endian)
 Push a packed greyscale buffer into the controller's frame RAM.
ra8_err_t ra8_epaper_display_area (const ra8_epaper_area_t *area, ra8_epaper_waveform_t waveform)
 Refresh the indicated rectangle on the physical panel.
ra8_err_t ra8_epaper_sleep (void)
 Drop the panel into deep-sleep (~15 uA per Waveshare AN).

Detailed Description

IT8951 e-paper controller SPI driver – public API.

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

Hand-written driver for the Waveshare / IT8951 e-paper timing controller. The IT8951 wraps the actual e-paper panel and exposes an SPI command/data interface to the host MCU. This driver is intended for a future custom carrier board (the EK-RA8D2 v1 dev-kit ships with a parallel TFT, not e-paper); the EPD demo apps that consume this driver compile but are gated off until the board is built.

The IT8951 SPI protocol is a "preamble" pattern documented in the IT8951 datasheet (rev 0.2 chapter 3.4 "SPI Interface" and chapter 4 "Application Note"; see also Waveshare's IT8951-AP user guide):

  • Every SPI transaction begins with a 16-bit preamble that tells the controller whether the controller is about to send a command (0x6000), send pixel data (0x0000), or read pixel/status data (0x1000).
  • For command writes the host then clocks the 16-bit command code MSB-first.
  • For data writes / reads the host clocks 16-bit words MSB-first until the transfer ends.
  • Between every preamble and the data phase the host must wait for the controller's "HRDY" GPIO to assert.

Public API surface:

Two properties of this controller are panel-specific and must not be baked into firmware:

  • VCOM is per-unit calibration data printed on each panel's own flex cable. A wrong value costs contrast immediately and damages the film cumulatively. This driver can read and write it but takes no view on what it should be; libs/ra8_epd_cal owns resolving it from durable per-device storage and fails safe when it cannot.
  • Waveform mode numbers are a property of the controller's firmware LUT and differ between panel sizes. They are supplied per panel through ra8_epaper_waveform_cfg_t.

Static allocation only – the driver keeps one panel context (s_panel) at file scope and rejects double-init.

Since
0.1.0

Definition in file ra8_epaper.h.

Enumeration Type Documentation

◆ ra8_epaper_dev_info_limits_t

Sizing of the GET_DEV_INFO (0x0302) response block.

Enumerator
k_ra8_epaper_ver_chars 

Chars in a FW / LUT version string.

Definition at line 213 of file ra8_epaper.h.

◆ ra8_epaper_endian_t

enum ra8_epaper_endian_t : uint8_t

Source-buffer endianness flag for the LD_IMG_AREA transfer.

IT8951 datasheet rev 0.2 chapter 4.1.5 – the panel can swap byte pairs on the fly so the host does not have to re-pack.

Enumerator
k_ra8_epaper_endian_little 

Host buffer is little-endian.

k_ra8_epaper_endian_big 

Host buffer is big-endian.

Definition at line 263 of file ra8_epaper.h.

◆ ra8_epaper_geom_limits_t

enum ra8_epaper_geom_limits_t : uint16_t

Geometry / waveform constants the driver enforces.

k_ra8_epaper_align_1bpp_px encodes the vendor requirement published on the Waveshare 6 inch HD wiki: "when we use 1bpp mode to update the 6inch e-Paper and 6inch HD e-Paper, we should align the X (begin point) and W (width) of the update area to four bytes (32bits), otherwise, the image cannot be displayed". Four bytes of a 1 bpp bitmap is 32 pixels, so both area->x and area->width must be multiples of 32 in 1 bpp mode. This is not a quality hint – a misaligned A2 update does not render at all.

See also
ra8_epaper_area_is_aligned
ra8_epaper_align_area
Enumerator
k_ra8_epaper_align_1bpp_px 

4-byte (32 px) X/W grid for 1 bpp.

k_ra8_epaper_wf_mode_max 

Highest valid LUT mode number.

Definition at line 204 of file ra8_epaper.h.

◆ ra8_epaper_pixel_format_t

enum ra8_epaper_pixel_format_t : uint8_t

Source pixel depth for a ra8_epaper_load_image transfer.

IT8951 datasheet rev 0.2 chapter 4.1.5 "Image Buffer Endianness" and the Waveshare IT8951 programming guide's IT8951_nBPP constants. These enumerators are driver-side selectors; the two-bit code the controller wants in the LD_IMG_AREA arg0 bitfield uses a different numbering (2 bpp = 0, 3 bpp = 1, 4 bpp = 2, 8 bpp = 3) and is applied internally by ra8_epaper_load_image.

Note
4 bpp is the right default for greyscale content. The panel renders 16 grey levels and the IT8951 keeps only the high nibble of an 8 bpp byte, so 4 bpp is visually identical to 8 bpp while halving the bytes on the wire – the largest cheap throughput win available on either SPI or I80.
Warning
1 bpp carries a hard geometry constraint that silently blanks the update when violated: see k_ra8_epaper_align_1bpp_px and ra8_epaper_align_area.
See also
ra8_epaper_bits_per_pixel
ra8_epaper_image_bytes
Enumerator
k_ra8_epaper_pf_1bpp 

1 bpp bi-level, 8 px per byte (A2).

k_ra8_epaper_pf_2bpp 

2 bpp, 4 px per byte.

k_ra8_epaper_pf_4bpp 

4 bpp, 2 px per byte – preferred.

k_ra8_epaper_pf_8bpp 

8 bpp, one byte per pixel.

Definition at line 180 of file ra8_epaper.h.

◆ ra8_epaper_waveform_t

enum ra8_epaper_waveform_t : uint8_t

Symbolic IT8951 panel-refresh waveform selectors.

IT8951 datasheet rev 0.2 chapter 4.1.4 "Display Update Modes" / Waveshare IT8951 application note table 2. Each waveform trades refresh latency for ghosting / quality.

Warning
These are selectors, not wire values. The number the controller actually wants in the DPY_AREA waveform argument is firmware-LUT dependent and differs per panel size – A2 is mode 4 on the M641 LUT (6 inch and 6 inch HD) but mode 6 on the 7.8 / 9.7 / 10.3 inch panels. The wire numbers therefore live in ra8_epaper_waveform_cfg_t, are supplied per panel through ra8_epaper_cfg_t, and are resolved by ra8_epaper_display_area. Never cast this enum onto the wire.
See also
ra8_epaper_waveform_cfg_t
ra8_epaper_waveform_cfg_for_lut
Enumerator
k_ra8_epaper_wf_init 

INIT - flush to white, slowest.

k_ra8_epaper_wf_du 

DU - direct update, 1 bpp, fast.

k_ra8_epaper_wf_gc16 

GC16 - 16-grey full quality.

k_ra8_epaper_wf_a2 

A2 - black/white only, fastest.

Definition at line 106 of file ra8_epaper.h.

Function Documentation

◆ 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_decode_dev_info()

ra8_err_t ra8_epaper_decode_dev_info ( const uint16_t * words,
size_t count,
ra8_epaper_dev_info_t * out_info )
nodiscard

Decode a raw GET_DEV_INFO word block into a device-info struct.

The controller answers GET_DEV_INFO with 20 big-endian-assembled words: panel width, panel height, the low and high halves of the image-buffer base address, then two 16-character version strings packed two ASCII chars per word. This is the pure decode half of that read – ra8_epaper_init buffers the words off the bus and calls this.

Version bytes outside printable ASCII are dropped to NUL, because the strings are logged and a controller that has not finished loading its waveform answers early reads with garbage.

Split out so the layout can be pinned by host tests with no controller attached: the decoded lut_version is what ra8_epaper_waveform_cfg_for_lut maps to a waveform mode number, so a mis-decode silently selects the wrong A2 mode on the panel.

Parameters
[in]wordsResponse words, most significant byte first as assembled by the bus layer; non-NULL.
[in]countNumber of words available in words; must be at least 20.
[out]out_infoReceives the decoded block; non-NULL. Fully overwritten, so it need not be pre-zeroed.
Returns
ra8_err_t error code.
Return values
k_ra8_okBlock decoded.
k_ra8_err_null_ptrwords or out_info is NULL.
k_ra8_err_invalid_argcount is below the 20-word layout.
Precondition
words holds at least count readable words.
out_info is writable.
Postcondition
On success fw_version and lut_version are NUL-terminated.
No bus traffic and no driver state mutated.
Note
Thread-safe: pure function over its arguments.
Example:
if (ra8_epaper_decode_dev_info(words, 20U, &info) == k_ra8_ok) {
}
ra8_err_t ra8_epaper_decode_dev_info(const uint16_t *words, size_t count, ra8_epaper_dev_info_t *out_info)
Decode a raw GET_DEV_INFO word block into a device-info struct.
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.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
Decoded GET_DEV_INFO (0x0302) response.
Definition ra8_epaper.h:247
char lut_version[k_ra8_epaper_ver_chars+1U]
LUT version, NUL-terminated.
Definition ra8_epaper.h:252
Per-panel map from ra8_epaper_waveform_t onto LUT mode numbers.
Definition ra8_epaper.h:148
See also
ra8_epaper_dev_info
ra8_epaper_waveform_cfg_for_lut
Since
0.1.0

Definition at line 161 of file ra8_epaper_devinfo.c.

References ra8_epaper_dev_info_t::fw_version, internal_ra8_epaper_decode_dev_word(), k_ra8_epaper_di_idx_end, k_ra8_epaper_ver_chars, k_ra8_err_invalid_arg, k_ra8_ok, ra8_epaper_dev_info_t::lut_version, RA8_CHECK_NULL_PTR, ra8_log_error, and s_tag.

Referenced by internal_ra8_epaper_read_dev_info().

◆ ra8_epaper_dev_info()

ra8_err_t ra8_epaper_dev_info ( ra8_epaper_dev_info_t * out_info)
nodiscard

Hand back the GET_DEV_INFO block captured during init.

ra8_epaper_init decodes the 40-byte response once and caches it, so this is an O(1) copy with no bus traffic.

Parameters
[out]out_infoReceives the decoded device block; non-NULL.
Returns
ra8_err_t error code.
Return values
k_ra8_okInfo copied.
k_ra8_err_null_ptrout_info is NULL.
k_ra8_err_invalid_statePanel never initialized.
Precondition
ra8_epaper_init succeeded.
out_info is writable.
Postcondition
*out_info mirrors the cached block.
No bus traffic and no driver state mutated.
Note
Thread-safe against other readers; not against ra8_epaper_init.
See also
ra8_epaper_dev_info_t
Since
0.1.0

Definition at line 701 of file ra8_epaper.c.

References k_ra8_epaper_state_ready, k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, s_panel, and s_tag.

◆ ra8_epaper_display_area()

ra8_err_t ra8_epaper_display_area ( const ra8_epaper_area_t * area,
ra8_epaper_waveform_t waveform )
nodiscard

Refresh the indicated rectangle on the physical panel.

Resolves waveform through the panel's ra8_epaper_waveform_cfg_t (supplied at init) into the LUT mode number this panel's controller firmware expects, issues DPY_AREA (0x0034) with area and that mode number, then polls REG_LUTAFSR (0x1224) until it reads zero (no LUTs busy). IT8951 datasheet rev 0.2 chapter 4.2.4.

This call enforces INV-VCOM-1. DPY_AREA is the command that puts a bias across the electrophoretic film, so it is refused outright unless ra8_epaper_set_vcom has programmed a VCOM and read it back unchanged. There is no override and no "just this once" path: a wrong or unknown bias damages the panel cumulatively with time under bias, and a blank screen is recoverable where a degraded panel is not. Stage pixels with ra8_epaper_load_image as much as you like beforehand – loading frame RAM applies no bias and is deliberately ungated.

Parameters
[in]areaRectangle to refresh (panel coords); non-NULL.
[in]waveformSymbolic waveform selector – not a wire value.
Returns
ra8_err_t error code.
Return values
k_ra8_okPanel idle and updated.
k_ra8_err_null_ptrarea is NULL.
k_ra8_err_invalid_statePanel never initialized.
k_ra8_err_validation_failedNo verified VCOM – INV-VCOM-1 refusal. Resolve one through ra8_epd_cal_resolve and apply it; do not retry blind.
k_ra8_err_invalid_argwaveform is not a known selector.
k_ra8_err_hw_timeoutLUT busy never cleared.
Precondition
ra8_epaper_load_image populated the area.
ra8_epaper_vcom_verified() is true.
Postcondition
The pixels of area match the most recent load.
The controller reports every LUT idle again.
Note
Not thread-safe.
See also
ra8_epaper_set_vcom
ra8_epaper_vcom_verified
ra8_epaper_waveform_cfg_for_lut
Since
0.1.0

Definition at line 927 of file ra8_epaper.c.

References internal_ra8_epaper_resolve_waveform(), internal_ra8_epaper_send_display_args(), internal_ra8_epaper_wait_lut_idle(), internal_ra8_epaper_write_cmd(), k_ra8_epaper_cmd_dpy_area, k_ra8_epaper_state_ready, k_ra8_err_invalid_state, k_ra8_err_validation_failed, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_log_error, s_panel, and s_tag.

Referenced by internal_eink_flush().

◆ 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_get_vcom()

ra8_err_t ra8_epaper_get_vcom ( uint16_t * out_mv)
nodiscard

Read the controller's current VCOM setting, in millivolts.

Issues the VCOM command (0x0039) with argument word 0x0000 ("get") and reads back one data word. The returned value is the magnitude of the panel common-electrode bias in millivolts: VCOM is always negative, so a panel labelled -1.53V reads back as 1530. Confirmed against the Waveshare IT8951 reference driver's EPD_IT8951_GetVCOM (USDEF_I80_CMD_VCOM = 0x0039).

Parameters
[out]out_mvReceives the VCOM magnitude in millivolts; non-NULL.
Returns
ra8_err_t error code.
Return values
k_ra8_okValue read.
k_ra8_err_null_ptrout_mv is NULL.
k_ra8_err_invalid_statePanel never initialized.
k_ra8_err_hw_timeoutHRDY stuck low.
Precondition
ra8_epaper_init succeeded.
out_mv is writable.
Postcondition
On success *out_mv holds the controller's VCOM magnitude.
No panel pixels are disturbed.
Note
Not thread-safe.
Warning
The value the controller powers up with is whatever its own driver board persisted. Treat it as a candidate to be range checked, never as authoritative – see ra8_epd_cal_resolve.
See also
ra8_epaper_set_vcom
Since
0.1.0

Definition at line 711 of file ra8_epaper.c.

References internal_ra8_epaper_read_data16(), internal_ra8_epaper_write_cmd(), internal_ra8_epaper_write_data16(), k_ra8_epaper_cmd_vcom, k_ra8_epaper_state_ready, k_ra8_epaper_vcom_get, k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, s_panel, and s_tag.

Referenced by ep_vcom_get(), and ra8_epaper_set_vcom().

◆ 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_init()

ra8_err_t ra8_epaper_init ( const ra8_epaper_cfg_t * cfg)
nodiscard

Bring up the IT8951 panel against the injected SPI bus seam.

Algorithm:

  1. Validate cfg (non-NULL bus.xfer8, sane panel geometry).
  2. Pulse the panel /RESET line (10 ms low / 10 ms high) so the IT8951 resets into a known state.
  3. Wait for HRDY to assert.
  4. Send SYS_RUN (0x0001) to take the controller out of standby.
  5. Send GET_DEV_INFO (0x0302) and consume the 40-byte response so the device's panel size matches cfg.

The SPI bus itself is app-owned: initialise the peripheral behind cfg->bus (mode 0, at most the IT8951's 24 MHz ceiling) before calling this.

Parameters
[in]cfgConfiguration descriptor.
Returns
ra8_err_t error code.
Return values
k_ra8_okPanel responsive and identified.
k_ra8_err_null_ptrcfg is NULL.
k_ra8_err_invalid_argcfg field out of range or cfg->bus.xfer8 NULL.
k_ra8_err_invalid_stateDriver already initialized.
k_ra8_err_hw_timeoutHRDY never asserted.
Precondition
The SPI peripheral behind cfg->bus is initialised (mode 0).
Reset / busy pins configured as GPIO output / input.
Postcondition
On success, the driver state machine is in k_ra8_epaper_state_ready and accepts load / display calls.
Note
Not thread-safe; called once during single-threaded init.
Since
0.1.0

Definition at line 654 of file ra8_epaper.c.

References internal_ra8_epaper_pulse_reset(), internal_ra8_epaper_read_dev_info(), internal_ra8_epaper_wait_ready(), internal_ra8_epaper_write_cmd(), k_ra8_epaper_cmd_sys_run, k_ra8_epaper_state_ready, k_ra8_epaper_state_uninit, k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_epaper_geometry_agrees(), ra8_epaper_validate_cfg(), ra8_log_error, ra8_log_info, ra8_log_warn, s_panel, and s_tag.

Referenced by internal_eink_init().

◆ ra8_epaper_load_image()

ra8_err_t ra8_epaper_load_image ( const ra8_epaper_area_t * area,
const uint8_t * buf,
size_t buf_len,
ra8_epaper_pixel_format_t pf,
ra8_epaper_endian_t endian )
nodiscard

Push a packed greyscale buffer into the controller's frame RAM.

Sends the LD_IMG_AREA (0x0021) command then streams buf over SPI. Internally:

  1. Set target frame address via REG_LISAR (0x0208 / 0x020A).
  2. Send LD_IMG_AREA + 5-arg block: endianness, pf, rotate, area.
  3. Stream buf 16-bit words MSB-first.
  4. Send LD_IMG_END (0x0022).

buf is packed at pf's depth, rows byte-aligned – exactly ra8_epaper_image_bytes(area, pf, ...) bytes. Prefer k_ra8_epaper_pf_4bpp for greyscale: it matches the panel's 16 grey levels, the controller discards the low nibble of 8 bpp data anyway, and it halves the wire time.

Parameters
[in]areaRectangle to update (panel coords); non-NULL. For k_ra8_epaper_pf_1bpp, x and width must be multiples of k_ra8_epaper_align_1bpp_px.
[in]bufPacked source buffer; non-NULL.
[in]buf_lenLength of buf in bytes; must equal ra8_epaper_image_bytes(area, pf, ...).
[in]pfSource pixel depth.
[in]endianSource endianness.
Returns
ra8_err_t error code.
Return values
k_ra8_okBuffer transferred.
k_ra8_err_null_ptrarea or buf is NULL.
k_ra8_err_invalid_statePanel never initialized.
k_ra8_err_invalid_sizebuf_len mismatch or empty area.
k_ra8_err_invalid_arg1 bpp rectangle violates the 32-pixel X/width alignment.
k_ra8_err_hw_timeoutHRDY stuck low.
Precondition
ra8_epaper_init succeeded.
buf_len matches area at depth pf.
Postcondition
Frame RAM holds the new pixel data; panel is NOT yet refreshed.
On any error path no partial area is marked for refresh.
Note
Not thread-safe.
See also
ra8_epaper_image_bytes
ra8_epaper_align_area
Since
0.1.0

Definition at line 837 of file ra8_epaper.c.

References internal_ra8_epaper_reg_write(), internal_ra8_epaper_send_load_args(), internal_ra8_epaper_stream_pixels(), internal_ra8_epaper_validate_load(), internal_ra8_epaper_write_cmd(), k_ra8_epaper_cmd_ld_img_area, k_ra8_epaper_cmd_ld_img_end, k_ra8_epaper_reg_lisar_hi, k_ra8_epaper_reg_lisar_lo, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by internal_eink_load_rect().

◆ ra8_epaper_set_vcom()

ra8_err_t ra8_epaper_set_vcom ( uint16_t mv)
nodiscard

Programme the controller's VCOM, verify it, and grant the INV-VCOM-1 permit.

Issues the VCOM command (0x0039) with argument word 0x0001 ("set") followed by mv, then immediately re-reads it with argument 0x0000 and compares. Confirmed against the Waveshare IT8951 reference driver's EPD_IT8951_SetVCOM.

The readback is not a diagnostic nicety, it is the invariant. A dead COPI line, a controller that quietly ignores the command, or a bus returning zeroes all accept the write and change nothing – a failure mode that is indistinguishable from success without the compare, and that would leave the film biased at whatever unknown value the controller powered up with. Only a matching readback sets the permit that ra8_epaper_display_area requires; any other outcome revokes it and the panel stays dark.

The permit is revoked on entry, so a failed call can never leave a previous call's permit standing, and it does not survive ra8_epaper_sleep.

Parameters
[in]mvVCOM magnitude in millivolts (the panel's label without its minus sign, e.g. 1530 for -1.53V). Must be non-zero; the driver has no way to know the panel's legal window and does not range-check beyond that – range checking against the panel's documented limits is ra8_epd_cal's job and must happen before this call.
Returns
ra8_err_t error code.
Return values
k_ra8_okVCOM programmed and read back equal; display commands are now permitted.
k_ra8_err_invalid_argmv is zero.
k_ra8_err_invalid_statePanel never initialized.
k_ra8_err_validation_failedThe controller echoed a different value. The link or the controller is not to be trusted with the bias; the panel stays un-drivable.
k_ra8_err_hw_timeoutHRDY stuck low.
Precondition
ra8_epaper_init succeeded.
mv was validated against the panel's documented VCOM window.
Postcondition
On success the controller reports the new VCOM and ra8_epaper_vcom_verified() is true.
On any failure ra8_epaper_vcom_verified() is false and every subsequent ra8_epaper_display_area is refused.
Note
Not thread-safe.
Warning
Driving a panel at the wrong VCOM damages it. The error is cumulative and not recoverable: a net DC bias across the electrophoretic film degrades contrast permanently, as a function of time under bias rather than refresh count. VCOM is per-unit calibration data printed on the panel's own flex cable; it must never be hardcoded in firmware. Resolve it through ra8_epd_cal_resolve and refuse to drive the panel when no trusted value exists.
Persistence across a power cycle is not established. The vendor reference driver re-sends VCOM on every run, which implies this command programs a volatile setting rather than the driver board's stored configuration. Re-apply it at every init and do not rely on it sticking.
See also
ra8_epaper_get_vcom
ra8_epaper_vcom_verified
ra8_epaper_display_area
Since
0.1.0

Programme the controller's VCOM, verify it, and grant the INV-VCOM-1 permit.

Definition at line 730 of file ra8_epaper.c.

References internal_ra8_epaper_write_cmd(), internal_ra8_epaper_write_data16(), k_ra8_epaper_cmd_vcom, k_ra8_epaper_state_ready, k_ra8_epaper_vcom_set, k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_err_validation_failed, k_ra8_ok, ra8_epaper_get_vcom(), ra8_log_error, s_panel, and s_tag.

Referenced by ep_vcom_set().

◆ ra8_epaper_sleep()

ra8_err_t ra8_epaper_sleep ( void )
nodiscard

Drop the panel into deep-sleep (~15 uA per Waveshare AN).

Issues SLEEP (0x0003). Subsequent calls require a fresh ra8_epaper_init because the controller forgets all register state.

Returns
ra8_err_t error code.
Return values
k_ra8_okPanel asleep.
k_ra8_err_invalid_statePanel never initialized.
Precondition
ra8_epaper_init succeeded.
Postcondition
Driver state machine is back in uninitialized; caller must re-init before any further load / display.
Note
Not thread-safe.
Since
0.1.0

Definition at line 961 of file ra8_epaper.c.

References internal_ra8_epaper_write_cmd(), k_ra8_epaper_cmd_sleep, k_ra8_epaper_state_ready, k_ra8_epaper_state_uninit, k_ra8_err_invalid_state, and s_panel.

Referenced by internal_eink_deinit().

◆ 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_vcom_verified()

bool ra8_epaper_vcom_verified ( void )
nodiscard

Report whether the INV-VCOM-1 permit is currently held.

True only while the driver is initialized and the most recent ra8_epaper_set_vcom read its value back unchanged. This is the exact predicate ra8_epaper_display_area enforces, exposed so an application can decide what to show (or, correctly, not show) without having to provoke a refused refresh to find out.

Returns
true when display commands are permitted, false otherwise.
Precondition
None; safe to call before ra8_epaper_init.
Postcondition
No bus traffic and no driver state mutated.
Note
Not thread-safe against ra8_epaper_set_vcom / _init / _sleep; safe against other readers.
See also
ra8_epaper_set_vcom
ra8_epaper_display_area
Since
0.1.0

Report whether the INV-VCOM-1 permit is currently held.

Definition at line 781 of file ra8_epaper.c.

References s_panel.

◆ 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().