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

CPU1-safe combined direction+level PORT primitive over PCNTR1/PCNTR2. More...

#include <stdint.h>
#include "ra8_err.h"
#include "ra8_port_constants.h"
#include "ra8_port_regs.h"
Include dependency graph for ra8_pcntr.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

static ra8_err_t ra8_pcntr_set_output (ra8_port_t port, ra8_pin_t pin, ra8_level_t level)
 Hold a pin an output and drive it to a level, via PCNTR1 (combined).
static ra8_err_t ra8_pcntr_read (ra8_port_t port, ra8_pin_t pin, ra8_level_t *out_level)
 Read a pin's live level from PCNTR2 (PIDR).

Detailed Description

CPU1-safe combined direction+level PORT primitive over PCNTR1/PCNTR2.

A deliberately tiny, header-only GPIO primitive built directly on the per-port PCNTR registers (ra8_port_regs.h). It exists so the secondary Cortex-M33 (CPU1) image – which is built -ffreestanding and links no ra8_hal (its only project include path is libs/ra8_core/inc, plus libs/ra8_hal/inc for the two freestanding-clean PORT headers) – can drive an on-chip pin through a HAL call instead of hand-rolling raw MMIO.

Why this is separate from ra8_port_utils.h

The high-level ra8_gpio_* driver (gpio.c) claims each pin through the pin-validator, logs through ra8_log, and programmes direction via the PFS register bank. Every one of those pulls infrastructure the freestanding M33 image does not link. This primitive intentionally depends on nothing but ra8_port_regs.h (the register layout + the ra8_port() accessor) and the typed enums in ra8_port_constants.h – all of which compile clean under -ffreestanding -fno-builtin – so it links into the CPU1 ELF unchanged, and it is host-testable on the ra8_fake_mmap peripheral-RAM backing exactly like the rest of the PORT layer.

Register model

Each port's PCNTR1 packs the direction latch PDR in bits [15:0] and the output latch PODR in bits [31:16]; PCNTR2 returns the live pin state PIDR in bits [15:0] (read-only). See ra8_port_regs.h and HUM Ch 20 "I/O Ports".

// Hold PORT6 pin 0 (EK-RA8D2 LED1, BLUE / P600) an output and drive it high:
(void)ra8_pcntr_read(k_ra8_port_0, k_ra8_pin_9, &sw1); // SW1 (P009), active-low
static ra8_err_t ra8_pcntr_read(ra8_port_t port, ra8_pin_t pin, ra8_level_t *out_level)
Read a pin's live level from PCNTR2 (PIDR).
Definition ra8_pcntr.h:162
static ra8_err_t ra8_pcntr_set_output(ra8_port_t port, ra8_pin_t pin, ra8_level_t level)
Hold a pin an output and drive it to a level, via PCNTR1 (combined).
Definition ra8_pcntr.h:99
@ k_ra8_port_6
RA8 port 6.
@ k_ra8_port_0
RA8 port 0.
ra8_level_t
Digital output / input level.
@ k_ra8_level_high
Drive or read 1.
@ k_ra8_pin_9
RA8 pin 9.
@ k_ra8_pin_0
RA8 pin 0.

Combined direction+level, and why read-modify-write

ra8_pcntr_set_output() sets BOTH direction (output) and level in one call – the combined-idiom the CPU1 images need – via a read-modify-write of PCNTR1 that preserves every other pin on the port. A bare full-word store to PCNTR1 (the ad-hoc form this primitive replaces) would silently force all sibling pins to input with a cleared output latch; the RMW here does not, so the primitive is safe to reuse on a shared port while remaining a drop-in substitute at the single-pin CPU1 call sites (their ports carry no other driven pins, so the observable pin state is identical).

Definition in file ra8_pcntr.h.

Function Documentation

◆ ra8_pcntr_read()

ra8_err_t ra8_pcntr_read ( ra8_port_t port,
ra8_pin_t pin,
ra8_level_t * out_level )
inlinestaticnodiscard

Read a pin's live level from PCNTR2 (PIDR).

Reads the port's PCNTR2 and reports the addressed pin's live input-data bit (PIDR[pin]) as a level. Works for a pin held an input or an output (PIDR reflects the actual pad state either way). Performs a single PCNTR2 read and touches nothing else. Any active-low interpretation (e.g. a push button) is left to the caller.

Parameters
[in]portPort index (k_ra8_port_0 .. k_ra8_port_max).
[in]pinPin index within the port (k_ra8_pin_0 .. k_ra8_pin_max).
[out]out_levelReceives the pin's level (k_ra8_level_low / k_ra8_level_high).
Returns
ra8_err_t error code.
Return values
k_ra8_ok*out_level holds the live pin level.
k_ra8_err_null_ptrout_level was nullptr.
k_ra8_err_gpio_invalid_portport is out of range.
k_ra8_err_gpio_invalid_pinpin is out of range.
k_ra8_err_hw_unmappedThe port has no register window (host fake only).
Precondition
The IOPORT module clock is on (always-on after reset on the RA8D2).
out_level points at writable storage.
Postcondition
On success, *out_level reflects PCNTR2.PIDR[pin].
On any failure, *out_level is left unmodified.
Note
ISR-safe and reentrant: a single volatile read of a read-only register, no shared state.
Since
0.1.0

Definition at line 162 of file ra8_pcntr.h.

References k_ra8_err_gpio_invalid_pin, k_ra8_err_gpio_invalid_port, k_ra8_err_hw_unmapped, k_ra8_err_null_ptr, k_ra8_level_high, k_ra8_level_low, k_ra8_ok, k_ra8_pin_max, k_ra8_port_max, r_port_regs_t::PCNTR2, pin, and ra8_port().

◆ ra8_pcntr_set_output()

ra8_err_t ra8_pcntr_set_output ( ra8_port_t port,
ra8_pin_t pin,
ra8_level_t level )
inlinestaticnodiscard

Hold a pin an output and drive it to a level, via PCNTR1 (combined).

Read-modify-writes the port's PCNTR1 so the addressed pin's direction latch (PDR) becomes output (1) and its output latch (PODR) reflects level, while every other pin's PDR/PODR bit is preserved. This is the single-call "set direction and level together" primitive the freestanding CPU1 images need; it performs one PCNTR1 read and one PCNTR1 write and touches nothing else (no PFS, no pin-validator, no logging).

Parameters
[in]portPort index (k_ra8_port_0 .. k_ra8_port_max).
[in]pinPin index within the port (k_ra8_pin_0 .. k_ra8_pin_max).
[in]levelTarget output level (k_ra8_level_low / k_ra8_level_high).
Returns
ra8_err_t error code.
Return values
k_ra8_okPin configured as output and driven to level.
k_ra8_err_gpio_invalid_portport is out of range.
k_ra8_err_gpio_invalid_pinpin is out of range.
k_ra8_err_hw_unmappedThe port has no register window (host fake only).
Precondition
The IOPORT module clock is on (always-on after reset on the RA8D2).
pin powers up routed to PORT (no PFS peripheral-mux setup is done here).
Postcondition
On success, PCNTR1.PDR[pin] == 1 (output) and PCNTR1.PODR[pin] equals level.
On success, no other pin's PDR/PODR bit on port is modified.
Note
Not thread-safe and not ISR-safe: the PCNTR1 read-modify-write is not atomic, so a concurrent update to another pin of the same port can race. Use during single-threaded init or with the relevant interrupts masked.
Since
0.1.0

Definition at line 99 of file ra8_pcntr.h.

References k_ra8_err_gpio_invalid_pin, k_ra8_err_gpio_invalid_port, k_ra8_err_hw_unmapped, k_ra8_level_high, k_ra8_ok, k_ra8_pcntr_high_half_shift, k_ra8_pin_max, k_ra8_port_max, r_port_regs_t::PCNTR1, pin, and ra8_port().

Referenced by blink_m33_hal_step().