ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_esp_hosted_gpio.c
Go to the documentation of this file.
1
28
29#include <stdint.h>
30
31#include "esp_hosted_power_save.h"
34#include "ra8_attributes.h"
35#include "ra8_check.h"
36#include "ra8_err.h"
38#include "ra8_esp_hosted_pins.h"
39#include "ra8_icu_regs.h"
40#include "ra8_log.h"
41#include "ra8_pin_interface.h"
42#include "ra8_port_constants.h"
43#include "ra8_port_utils.h"
44#include "ra8_reset.h"
45
55static const char* const s_tag = "eh_gpio";
56
73typedef enum : uint32_t {
76
96
116
136
137static_assert((uint32_t)k_ra8_esp_hosted_gpio_mode_input == (uint32_t)H_GPIO_MODE_DEF_INPUT,
138 "input mode selector must match the vendored spelling");
139static_assert((uint32_t)k_ra8_esp_hosted_gpio_mode_output == (uint32_t)H_GPIO_MODE_DEF_OUTPUT,
140 "output mode selector must match the vendored spelling");
141static_assert((uint32_t)k_ra8_esp_hosted_gpio_pull_up == (uint32_t)H_GPIO_PULL_UP,
142 "pull-up selector must match the vendored spelling");
143static_assert((uint32_t)k_ra8_esp_hosted_gpio_pull_down == (uint32_t)H_GPIO_PULL_DOWN,
144 "pull-down selector must match the vendored spelling");
145static_assert((uint8_t)H_HS_INTR_EDGE <= (uint8_t)k_ra8_icu_irqmd_low,
146 "HANDSHAKE edge selector must be a legal ICU sense");
147static_assert((uint8_t)H_DR_INTR_EDGE <= (uint8_t)k_ra8_icu_irqmd_low,
148 "DATA_READY edge selector must be a legal ICU sense");
149
178
191
203
204/*
205 * The production pin driver is defined in libs/ra8_hal/src/gpio.c and, like
206 * every other consumer of it in this tree, is reached by declaration rather
207 * than through a header -- ra8_pin_interface.h describes the type, not the
208 * instance.
209 */
211
213 uint32_t gpio_num,
214 ra8_port_pin_t* out_pin)
215{
216 if (out_pin == nullptr) {
217 return false;
218 }
219 const uintptr_t port_idx = (uintptr_t)gpio_port;
220 if ((gpio_num == (uint32_t)k_ra8_esp_hosted_gpio_pin_unwired) ||
221 (port_idx > (uintptr_t)k_ra8_port_max) || (gpio_num > (uint32_t)k_ra8_pin_max)) {
222 return false;
223 }
224 *out_pin = RA8_PIN((uint16_t)port_idx, (uint16_t)gpio_num);
225 return true;
226}
227
232
237
265{
266 for (uint8_t i = 0U; i < (uint8_t)k_ra8_esp_hosted_gpio_row_max; i++) {
267 if (s_irq_rows[i].used && (s_irq_rows[i].pin == pin)) {
268 return i;
269 }
270 }
271 return (uint8_t)k_ra8_esp_hosted_gpio_row_max;
272}
273
298static uint8_t internal_irq_alloc(void)
299{
300 for (uint8_t i = 0U; i < (uint8_t)k_ra8_esp_hosted_gpio_row_max; i++) {
301 if (!s_irq_rows[i].used) {
302 return i;
303 }
304 }
305 return (uint8_t)k_ra8_esp_hosted_gpio_row_max;
306}
307
333{
335 row->handler(row->arg);
336}
337
371 uint8_t irq_num,
372 uint8_t sense,
373 void (*handler)(void*),
374 void* arg)
375{
376 const uint8_t slot = internal_irq_alloc();
377 if (slot >= (uint8_t)k_ra8_esp_hosted_gpio_row_max) {
378 return k_ra8_err_no_mem;
379 }
380 s_irq_rows[slot].pin = pin;
381 s_irq_rows[slot].handler = handler;
382 s_irq_rows[slot].arg = arg;
383 s_irq_rows[slot].irq_num = irq_num;
384 s_irq_rows[slot].used = true;
385
386 const ra8_gpio_irq_cfg_t cfg = {
387 .pull = k_ra8_pull_none,
388 .sense = (ra8_icu_irqmd_t)sense,
389 .filter_div = k_ra8_icu_fclksel_pclkb,
390 .filter_en = false,
391 .priority = (uint8_t)k_ra8_esp_hosted_gpio_irq_priority,
392 };
393 const ra8_err_t err =
395 if (err != k_ra8_ok) {
397 ra8_log_error_val(s_tag, "attach_irq failed", (uint32_t)err);
398 }
399 return err;
400}
401
431static int internal_config_gpio(void* gpio_port, uint32_t gpio_num, uint32_t mode)
432{
434 if (!priv_ra8_esp_hosted_gpio_decode_pin(gpio_port, gpio_num, &pin)) {
435 return RET_INVALID;
436 }
438 if (mode == (uint32_t)k_ra8_esp_hosted_gpio_mode_output) {
440 err = pin_if->output_init(pin_if->ctx, pin, (ra8_level_t)H_RESET_VAL_INACTIVE);
441 } else if (mode == (uint32_t)k_ra8_esp_hosted_gpio_mode_input) {
443 } else {
444 return RET_INVALID;
445 }
446 return (err == k_ra8_ok) ? RET_OK : RET_FAIL;
447}
448
481static int internal_config_gpio_as_interrupt(void* gpio_port,
482 uint32_t gpio_num,
483 uint32_t intr_type,
484 void (*gpio_isr_handler)(void* arg),
485 void* arg)
486{
488 if (!priv_ra8_esp_hosted_gpio_decode_pin(gpio_port, gpio_num, &pin)) {
489 return RET_INVALID;
490 }
491 if (gpio_isr_handler == nullptr) {
492 return RET_INVALID;
493 }
494 if (intr_type > (uint32_t)k_ra8_icu_irqmd_low) {
495 return RET_INVALID;
496 }
498 return RET_FAIL;
499 }
500
501 const uint8_t irq_num = ra8_esp_hosted_pin_irq_num(pin);
502 const uint8_t sense = (uint8_t)intr_type;
503 const ra8_err_t err =
504 (irq_num == (uint8_t)k_ra8_esp_hosted_irq_none)
505 ? priv_ra8_esp_hosted_gpio_edge_register(pin, sense, gpio_isr_handler, arg)
506 : internal_attach_hardware(pin, irq_num, sense, gpio_isr_handler, arg);
507 return (err == k_ra8_ok) ? RET_OK : RET_FAIL;
508}
509
538static int internal_teardown_gpio_interrupt(void* gpio_port, uint32_t gpio_num)
539{
541 if (!priv_ra8_esp_hosted_gpio_decode_pin(gpio_port, gpio_num, &pin)) {
542 return RET_INVALID;
543 }
544 const uint8_t slot = internal_irq_find(pin);
545 if (slot >= (uint8_t)k_ra8_esp_hosted_gpio_row_max) {
547 }
548 const ra8_err_t err = ra8_gpio_detach_irq(pin, s_irq_rows[slot].irq_num);
550 return (err == k_ra8_ok) ? RET_OK : RET_FAIL;
551}
552
581static int internal_read_gpio(void* gpio_port, uint32_t gpio_num)
582{
584 if (!priv_ra8_esp_hosted_gpio_decode_pin(gpio_port, gpio_num, &pin)) {
585 return RET_INVALID;
586 }
589 if (pin_if->read(pin_if->ctx, pin, &level) != k_ra8_ok) {
590 return RET_FAIL;
591 }
594}
595
622static int internal_write_gpio(void* gpio_port, uint32_t gpio_num, uint32_t value)
623{
625 if (!priv_ra8_esp_hosted_gpio_decode_pin(gpio_port, gpio_num, &pin)) {
626 return RET_INVALID;
627 }
629 const ra8_level_t level = (value != 0U) ? k_ra8_level_high : k_ra8_level_low;
630 return (pin_if->write(pin_if->ctx, pin, level) == k_ra8_ok) ? RET_OK : RET_FAIL;
631}
632
667static int
668internal_pull_gpio(void* gpio_port, uint32_t gpio_num, uint32_t pull_value, uint32_t enable)
669{
671 if (!priv_ra8_esp_hosted_gpio_decode_pin(gpio_port, gpio_num, &pin)) {
672 return RET_INVALID;
673 }
674 if (pull_value == (uint32_t)k_ra8_esp_hosted_gpio_pull_down) {
675 ra8_log_warn(s_tag, "pull-down requested; RA8D2 PFS has no pull-down bit");
676 return RET_FAIL;
677 }
678 if (pull_value != (uint32_t)k_ra8_esp_hosted_gpio_pull_up) {
679 return RET_INVALID;
680 }
681 const ra8_pin_pull_t pull = (enable != 0U) ? k_ra8_pull_up : k_ra8_pull_none;
682 (void)ra8_gpio_release(pin);
683 return (ra8_gpio_input_init(pin, pull) == k_ra8_ok) ? RET_OK : RET_FAIL;
684}
685
725static int internal_hold_gpio(void* gpio_port, uint32_t gpio_num, uint32_t hold_value)
726{
727 (void)hold_value;
729 if (!priv_ra8_esp_hosted_gpio_decode_pin(gpio_port, gpio_num, &pin)) {
730 return RET_INVALID;
731 }
732 ra8_log_warn(s_tag, "pin hold unavailable: no per-pin retention control in ra8_hal");
733 ra8_log_info_val(s_tag, "hold refused for pin", (uint32_t)pin);
734 ra8_log_info_val(s_tag, "hold value requested", hold_value);
735 return RET_FAIL;
736}
737
765{
767 if (ra8_reset_get_cause(&cause) != k_ra8_ok) {
768 return (int)HOSTED_WAKEUP_UNDEFINED;
769 }
771 return (int)HOSTED_WAKEUP_DEEP_SLEEP;
772 }
773 return (int)HOSTED_WAKEUP_NORMAL_REBOOT;
774}
775
777{
778 RA8_CHECK_NULL_PTR(out, s_tag, "vtable must not be nullptr");
779 out->_h_config_gpio = internal_config_gpio;
780 out->_h_config_gpio_as_interrupt = internal_config_gpio_as_interrupt;
781 out->_h_teardown_gpio_interrupt = internal_teardown_gpio_interrupt;
782 out->_h_read_gpio = internal_read_gpio;
783 out->_h_write_gpio = internal_write_gpio;
784 out->_h_pull_gpio = internal_pull_gpio;
785 out->_h_hold_gpio = internal_hold_gpio;
786 out->_h_get_host_wakeup_or_reboot_reason = internal_wakeup_reason;
787 return (out->_h_read_gpio != nullptr) ? k_ra8_ok : k_ra8_err_invalid_state;
788}
const ra8_pin_interface_t g_ra8_gpio_pin_interface
Definition gpio.c:502
esp-hosted port header: transport selection, side-band pin map, link polarity.
#define H_DR_INTR_EDGE
Interrupt sense the port programs for the DATA_READY input.
#define H_HS_INTR_EDGE
Interrupt sense the port programs for the HANDSHAKE input.
#define H_RESET_VAL_INACTIVE
Level that releases the co-processor from reset.
esp-hosted port header: RTOS handle types, return codes and budgets.
#define H_GPIO_PULL_DOWN
Select the internal pull-down when configuring a pin.
#define H_GPIO_MODE_DEF_INPUT
Configure a side-band pin as a digital input.
#define H_GPIO_MODE_DEF_OUTPUT
Configure a side-band pin as a push-pull digital output.
#define RET_FAIL
Operation failed for an unspecified reason.
#define RET_INVALID
A parameter was out of contract (null handle, bad size).
#define RET_OK
Operation completed.
#define H_GPIO_PULL_UP
Select the internal pull-up when configuring a pin.
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_ISR_SAFE
The function is callable from interrupt context.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
ra8_board_eth_pin_t pin
Pin.
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
Definition ra8_err.h:142
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
ra8_esp_hosted_gpio_read_t
Values _h_read_gpio returns for a successful read.
@ k_ra8_esp_hosted_gpio_read_high
Pin read high.
@ k_ra8_esp_hosted_gpio_read_low
Pin read low.
static const ra8_pin_interface_t * s_pin_if
The pin driver every level read and write goes through.
void priv_ra8_esp_hosted_gpio_set_pin_interface(const ra8_pin_interface_t *iface)
Replace the pin driver the slice reads and writes levels through.
static int internal_wakeup_reason(void)
_h_get_host_wakeup_or_reboot_reason: why the host last started.
static int internal_write_gpio(void *gpio_port, uint32_t gpio_num, uint32_t value)
_h_write_gpio: drive a side-band output.
static int internal_hold_gpio(void *gpio_port, uint32_t gpio_num, uint32_t hold_value)
_h_hold_gpio: freeze a pin's state across deep sleep.
static int internal_config_gpio(void *gpio_port, uint32_t gpio_num, uint32_t mode)
_h_config_gpio: put a side-band pin in a plain digital mode.
static uint8_t internal_irq_alloc(void)
Take the first free interrupt row.
bool priv_ra8_esp_hosted_gpio_decode_pin(const void *gpio_port, uint32_t gpio_num, ra8_port_pin_t *out_pin)
Decode the vendored (void* port, uint32_t pin) pair into a pin.
static ra8_err_t internal_attach_hardware(ra8_port_pin_t pin, uint8_t irq_num, uint8_t sense, void(*handler)(void *), void *arg)
Attach a pin to a real ICU external-interrupt channel.
ra8_err_t priv_ra8_esp_hosted_gpio_bind(hosted_osi_funcs_t *out)
Populate the eight GPIO slots of the OS-abstraction vtable.
static void internal_isr_trampoline(void *ctx)
ICU handler shim that calls the vendored side-band callback.
const ra8_pin_interface_t * priv_ra8_esp_hosted_gpio_pin_interface(void)
Report the pin driver currently installed in the slice.
ra8_esp_hosted_gpio_mode_t
Pin directions _h_config_gpio accepts.
@ k_ra8_esp_hosted_gpio_mode_input
Digital input.
@ k_ra8_esp_hosted_gpio_mode_output
Push-pull digital output.
struct ra8_esp_hosted_gpio_irq_row ra8_esp_hosted_gpio_irq_row_t
ra8_esp_hosted_gpio_pull_t
Pull selectors _h_pull_gpio accepts.
@ k_ra8_esp_hosted_gpio_pull_up
Internal pull-up.
@ k_ra8_esp_hosted_gpio_pull_down
Internal pull-down (no silicon).
static ra8_esp_hosted_gpio_irq_row_t s_irq_rows[k_ra8_esp_hosted_gpio_row_max]
Pins currently attached to an ICU external-interrupt channel.
static int internal_config_gpio_as_interrupt(void *gpio_port, uint32_t gpio_num, uint32_t intr_type, void(*gpio_isr_handler)(void *arg), void *arg)
_h_config_gpio_as_interrupt: watch a side-band pin for an edge.
ra8_esp_hosted_gpio_sentinel_t
The "signal is not wired" pin value as it arrives at a slot.
@ k_ra8_esp_hosted_gpio_pin_unwired
-1 widened to 32 bits.
static int internal_read_gpio(void *gpio_port, uint32_t gpio_num)
_h_read_gpio: sample the raw logic level of a side-band pin.
static int internal_teardown_gpio_interrupt(void *gpio_port, uint32_t gpio_num)
_h_teardown_gpio_interrupt: stop watching a side-band pin.
static uint8_t internal_irq_find(ra8_port_pin_t pin)
Find the interrupt row watching a pin.
static int internal_pull_gpio(void *gpio_port, uint32_t gpio_num, uint32_t pull_value, uint32_t enable)
_h_pull_gpio: enable or disable an internal pull on a pin.
ra8_err_t priv_ra8_esp_hosted_gpio_edge_register(ra8_port_pin_t pin, uint8_t sense, void(*handler)(void *), void *arg)
Take a pin under software edge detection.
ra8_err_t priv_ra8_esp_hosted_gpio_edge_unregister(ra8_port_pin_t pin)
Drop a pin from software edge detection.
Module-private surface of the esp-hosted side-band GPIO slice.
@ k_ra8_esp_hosted_gpio_row_max
Rows in the polled edge table; also the registration ceiling.
@ k_ra8_esp_hosted_gpio_irq_priority
NVIC priority given to a hardware side-band edge.
THE single point of change for the RA8 <-> ESP32-C6 harness map.
@ k_ra8_esp_hosted_irq_none
No ICU channel routes this pin.
uint8_t ra8_esp_hosted_pin_irq_num(ra8_port_pin_t pin)
Report the ICU external-interrupt channel that serves a pin.
Interrupt Control Unit (ICU) register layout for the Renesas RA8D2.
@ k_ra8_icu_fclksel_pclkb
00: sample every PCLKB cycle.
ra8_icu_irqmd_t
IRQCRi.IRQMD[1:0] detection sense values (HUM 14.2.12 p 535).
@ k_ra8_icu_irqmd_low
11: low-level sensitive.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_warn(tag, message)
RA8 log warn.
Definition ra8_log.h:347
#define ra8_log_info_val(tag, message, value)
RA8 log info val.
Definition ra8_log.h:366
#define ra8_log_error_val(tag, message, value)
RA8 log error val.
Definition ra8_log.h:337
Abstract pin-driver interface for dependency injection.
Typed Port / Pin Constants for the RA8D2 IOPORT Module.
ra8_port_pin_t
Packed (port << 8) | pin pin identifier.
@ k_ra8_pin_none
Sentinel: no pin selected.
@ k_ra8_port_max
Highest valid port index.
#define RA8_PIN(port, pin)
Build a ra8_port_pin_t from explicit port / pin indices.
ra8_level_t
Digital output / input level.
@ k_ra8_level_high
Drive or read 1.
@ k_ra8_level_low
Drive or read 0.
@ k_ra8_pin_max
Highest valid pin index.
ra8_pin_pull_t
Pull-up/pull-down selection (where supported).
@ k_ra8_pull_none
No internal pull.
@ k_ra8_pull_up
Internal pull-up.
High-level GPIO helpers on top of the PORT + PFS register layer.
ra8_err_t ra8_gpio_input_init(ra8_port_pin_t pin, ra8_pin_pull_t pull)
Configure a pin as a digital input.
Definition gpio.c:121
ra8_err_t ra8_gpio_detach_irq(ra8_port_pin_t pin, uint8_t irq_num)
Tear down a previously attached external IRQ.
Definition gpio.c:388
ra8_err_t ra8_gpio_release(ra8_port_pin_t pin)
Release a GPIO pin claim.
Definition gpio.c:233
ra8_err_t ra8_gpio_attach_irq(ra8_port_pin_t pin, uint8_t irq_num, const ra8_gpio_irq_cfg_t *cfg, ra8_isr_handler_t handler, void *ctx)
Wire a pin as an external IRQ input and install a handler.
Definition gpio.c:341
Reset cause introspection + software reset trigger.
ra8_err_t ra8_reset_get_cause(ra8_reset_cause_t *out)
Decode the latched RSTSRn flags into a single primary cause.
Definition ra8_reset.c:326
ra8_reset_cause_t
Decoded reset-cause taxonomy.
Definition ra8_reset.h:93
@ k_ra8_reset_cause_deep_sw_standby
RSTSR0.DPSRSTF.
Definition ra8_reset.h:101
@ k_ra8_reset_cause_unknown
No flag latched.
Definition ra8_reset.h:94
One pin served by a real ICU external-interrupt channel.
ra8_port_pin_t pin
Packed pin the channel watches.
uint8_t irq_num
ICU external-interrupt channel, 0..15.
bool used
True while the row is occupied.
void(* handler)(void *arg)
Vendored callback to invoke.
void * arg
Opaque argument for handler.
Configuration descriptor for ra8_gpio_attach_irq.
Vtable for a pin driver.
ra8_err_t(* output_init)(void *ctx, ra8_port_pin_t pin, ra8_level_t init_level)
Configure a pin as an output at an initial level.
void * ctx
Opaque context handed to every call.
ra8_err_t(* write)(void *ctx, ra8_port_pin_t pin, ra8_level_t level)
Drive a pin.
ra8_err_t(* read)(void *ctx, ra8_port_pin_t pin, ra8_level_t *out_level)
Read a pin.