ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
board_periph_gpio.c
Go to the documentation of this file.
1
21
22#include <stdint.h>
23#include <stdio.h>
24
25#include "board_console.h"
26#include "board_periph.h"
27#include "board_periph_block.h"
28#include "board_periph_eink.h"
30
32typedef enum : uint32_t {
36
38typedef enum : uint32_t {
41
43typedef enum : uint64_t {
44 k_port_base = 0x40400000UL,
45 k_port_stride = 0x20UL,
46 k_port_count = 15UL,
47 k_port_span = 0x20UL * 15UL,
48 k_port_pcntr1 = 0x00UL,
49 k_port_pcntr2 = 0x04UL,
50 k_port_pcntr3 = 0x08UL,
51 k_port_pcntr4 = 0x0CUL,
53
55typedef enum : uint32_t {
57 k_half_mask = 0xFFFFU,
60
62typedef enum : uint32_t {
63 k_sw_port = 0U,
64 k_sw1_pin = 9U,
65 k_sw2_pin = 8U,
66} sw_pin_t;
67
69typedef enum : uint16_t {
72 k_led_rgb565_red = 0xF800U,
74
76typedef struct {
77 uint16_t pdr;
78 uint16_t podr;
79 uint16_t in_ovr;
80 uint16_t in_lvl;
82
84typedef struct {
85 uint8_t port;
86 uint8_t pin;
87 uint16_t color;
88 const char* name;
89} led_map_t;
90
92 {6U, 0U, (uint16_t)k_led_rgb565_blue, "LED1 BLUE P600"},
93 {3U, 3U, (uint16_t)k_led_rgb565_green, "LED2 GREEN P303"},
94 {(uint8_t)k_led3_port, (uint8_t)k_led3_pin, (uint16_t)k_led_rgb565_red, "LED3 RED PA07"},
95};
96
100
112RA8_INTERNAL static void
113internal_port_trace_leds(uint32_t port_idx, uint16_t before, uint16_t after)
114{
115 for (uint32_t i = 0U; i < (uint32_t)k_board_led_count; i++) {
116 if (s_k_led_map[i].port != (uint8_t)port_idx) {
117 continue;
118 }
119 const uint16_t mask = (uint16_t)(1U << s_k_led_map[i].pin);
120 const uint32_t was = ((before & mask) != 0U) ? 1U : 0U;
121 const uint32_t now = ((after & mask) != 0U) ? 1U : 0U;
122 if (was != now) {
123 s_led_level[i] = now;
125 /* Console GPIO tab: one line per pin-level edge (bounded -- only the mapped
126 * board LEDs, and only on a 0<->1 change, so a blink loop cannot flood). */
128 (void)snprintf(ln, sizeof(ln), "%s -> %s", s_k_led_map[i].name, now ? "ON" : "OFF");
130 if (board_periph_trace()) {
131 (void)priv_emu_io_errf(" [trace] %s -> %s\n", s_k_led_map[i].name, now ? "ON" : "OFF");
132 }
133 }
134 }
135}
136
147RA8_INTERNAL static void internal_port_set_podr(uint32_t port_idx, uint16_t new_podr)
148{
149 const uint16_t old = s_port[port_idx].podr;
150 if (old != new_podr) {
151 internal_port_trace_leds(port_idx, old, new_podr);
152 s_port[port_idx].podr = new_podr;
153 }
154}
155
169RA8_INTERNAL static uint64_t internal_port_read(uc_engine* uc, uint64_t addr, unsigned size)
170{
171 (void)uc;
172 (void)size;
173 const uint32_t idx = (uint32_t)((addr - (uint64_t)k_port_base) / (uint64_t)k_port_stride);
174 const uint64_t off = (addr - (uint64_t)k_port_base) % (uint64_t)k_port_stride;
175 if (idx >= (uint32_t)k_port_count) {
176 return 0U;
177 }
178 const port_state_t* p = &s_port[idx];
179 if (off == (uint64_t)k_port_pcntr1) {
180 return ((uint32_t)p->podr << (uint32_t)k_half_shift) | (uint32_t)p->pdr;
181 }
182 if (off == (uint64_t)k_port_pcntr2) {
183 /* PIDR reads the live pin level: an output pin reads back its driven latch
184 * (so a "read what I drove" check is honest); an input pin reads any
185 * externally-injected level (user buttons -- see board_periph_gpio_set_input),
186 * else 0. */
187 const uint16_t driven = (uint16_t)(p->podr & p->pdr);
188 const uint16_t inputs = (uint16_t)((uint16_t)(~p->pdr) & p->in_ovr & p->in_lvl);
189 return (uint32_t)(uint16_t)(driven | inputs);
190 }
191 return 0U; /* PCNTR3 is write-only; PCNTR4 unmodelled -> 0. */
192}
193
206RA8_INTERNAL static void
207internal_port_write(uc_engine* uc, uint64_t addr, unsigned size, uint64_t value)
208{
209 (void)uc;
210 (void)size;
211 const uint32_t idx = (uint32_t)((addr - (uint64_t)k_port_base) / (uint64_t)k_port_stride);
212 const uint64_t off = (addr - (uint64_t)k_port_base) % (uint64_t)k_port_stride;
213 if (idx >= (uint32_t)k_port_count) {
214 return;
215 }
216 if (off == (uint64_t)k_port_pcntr1) {
217 s_port[idx].pdr = (uint16_t)(value & (uint32_t)k_half_mask);
219 idx,
220 (uint16_t)(((uint32_t)value >> (uint32_t)k_half_shift) & (uint32_t)k_half_mask));
221 } else if (off == (uint64_t)k_port_pcntr3) {
222 const uint16_t posr = (uint16_t)((uint32_t)value & (uint32_t)k_half_mask);
223 const uint16_t porr =
224 (uint16_t)(((uint32_t)value >> (uint32_t)k_half_shift) & (uint32_t)k_half_mask);
225 uint16_t podr = s_port[idx].podr;
226 podr |= posr; /* atomic set */
227 podr &= (uint16_t)~porr; /* atomic clear */
228 internal_port_set_podr(idx, podr);
229 }
230}
231
241{
242 for (uint32_t i = 0U; i < (uint32_t)k_port_count; i++) {
243 s_port[i] = (port_state_t){};
244 }
245 /* EK-RA8D2 user switches are active-low with pull-ups: idle (released) reads
246 * high. Seed P009/P008 (SW1/SW2) high so a firmware poll sees "not pressed"
247 * until board_periph_gpio_set_input() drives them low (a --button press). */
248 const uint16_t sw_mask = (uint16_t)((1U << (uint32_t)k_sw1_pin) | (1U << (uint32_t)k_sw2_pin));
249 s_port[k_sw_port].in_ovr |= sw_mask;
250 s_port[k_sw_port].in_lvl |= sw_mask;
251 for (uint32_t i = 0U; i < (uint32_t)k_board_led_count; i++) {
252 s_led_level[i] = 0U;
253 s_led_transitions[i] = 0U;
254 }
255 /* An attached --eink IT8951 controller re-arms its HRDY "ready" GPIO input
256 * high here, AFTER the ports are cleared, so the firmware's ra8_epaper HRDY
257 * poll reads ready (a no-op when no controller is attached). Mirrors the
258 * user-switch seeding above. */
260}
261
262void board_periph_gpio_set_input(uint8_t port, uint8_t pin, bool level)
263{
264 if ((uint32_t)port >= (uint32_t)k_port_count || (uint32_t)pin >= (uint32_t)k_pins_per_port) {
265 return;
266 }
267 const uint16_t bit = (uint16_t)(1U << (uint32_t)pin);
268 s_port[port].in_ovr |= bit;
269 if (level) {
270 s_port[port].in_lvl |= bit;
271 } else {
272 s_port[port].in_lvl &= (uint16_t)~bit;
273 }
274}
275
276bool board_periph_gpio_get_input(uint8_t port, uint8_t pin)
277{
278 if ((uint32_t)port >= (uint32_t)k_port_count || (uint32_t)pin >= (uint32_t)k_pins_per_port) {
279 return false;
280 }
281 const uint16_t bit = (uint16_t)(1U << (uint32_t)pin);
282 return (s_port[port].in_lvl & bit) != 0U;
283}
284
286{
287 if ((uint32_t)led >= (uint32_t)k_board_led_count) {
288 return 0U;
289 }
290 return s_led_level[(uint32_t)led];
291}
292
294{
295 if ((uint32_t)led >= (uint32_t)k_board_led_count) {
296 return 0U;
297 }
298 return s_k_led_map[(uint32_t)led].color;
299}
300
310{
311 (void)priv_emu_io_errf(" GPIO LEDs :");
312 for (uint32_t i = 0U; i < (uint32_t)k_board_led_count; i++) {
313 (void)priv_emu_io_errf(" [%s %s x%u]",
314 s_k_led_map[i].name,
315 s_led_level[i] ? "ON" : "OFF",
317 }
318 (void)priv_emu_io_errf("\n");
319}
320
323 .base = (uint64_t)k_port_base,
324 .span = (uint64_t)k_port_span,
325 .order = (uint32_t)k_block_order_gpio,
326 .read = internal_port_read,
328 .tick = nullptr,
329 .reset = internal_port_reset,
330 .report = internal_port_report,
331 .name = "GPIO/PORT",
332};
333
Multi-channel console log store backing the board view's tabbed console.
void board_console_push(board_console_ch_t ch, const char *line)
Append one completed line to a channel ring and the ALL ring.
@ k_board_console_ch_gpio
GPIO / PORT pin-level transitions.
Register-accurate peripheral-model framework for the board emulator.
board_led_id_t
Board user-LED identity, mirrored from the EK-RA8D2 BSP.
@ k_board_led_count
Board led count.
Decentralized peripheral-block registry for the board emulator core.
void board_periph_register_block(const board_periph_block_t *block)
Register a peripheral block's descriptor with the core registry.
@ k_block_order_gpio
GPIO/PORT (no tick today).
bool board_periph_trace(void)
Whether –trace is active (blocks log transitions when true).
IT8951 e-paper SPI-device model for ra8_emulator (attached to SPI_B).
void board_eink_apply_gpio_defaults(void)
Re-arm the panel HRDY "ready" GPIO input high (if attached).
static port_state_t s_port[k_port_count]
uint32_t board_periph_led_level(board_led_id_t led)
Read the last driven output level of a board LED.
static RA8_INTERNAL void internal_port_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value)
Dispatch a PORT register write (PCNTR1 direction/latch, PCNTR3 set/clear).
gpio_console_t
Console-tap line buffer capacity for a GPIO edge summary.
@ k_gpio_console_line_cap
Max chars in a "NAME -> ON/OFF" line.
static RA8_INTERNAL void internal_port_trace_leds(uint32_t port_idx, uint16_t before, uint16_t after)
Note a board-LED edge when a traced port/pin output latch changes.
static RA8_INTERNAL void internal_port_set_podr(uint32_t port_idx, uint16_t new_podr)
Apply a new PODR value to a port and trace any LED transition.
static RA8_INTERNAL void internal_board_periph_gpio_register(void)
Self-register the GPIO block before main runs (decentralized).
static const led_map_t s_k_led_map[k_board_led_count]
gpio_lit_t
LED3 PORT/pin coordinates on the EK-RA8D2 (P10_07).
@ k_led3_pin
Led3 pin.
@ k_led3_port
Led3 port.
static uint32_t s_led_transitions[k_board_led_count]
0->1 / 1->0 count.
port_field_t
Generic field shifts / masks shared by the PORT halves.
@ k_half_shift
High-half (PODR/PORR/EIDR) shift.
@ k_half_mask
16-bit half mask.
@ k_pins_per_port
Pins per PORT instance.
static const board_periph_block_t s_k_gpio_block
This block's descriptor (static lifetime; the core keeps the pointer).
static RA8_INTERNAL void internal_port_report(void)
Print the board-LED final level and transition-count line.
static RA8_INTERNAL uint64_t internal_port_read(uc_engine *uc, uint64_t addr, unsigned size)
Dispatch a PORT register read; returns PCNTR value for the port.
uint16_t board_periph_led_color_rgb565(board_led_id_t led)
The on-colour of a board LED as a packed RGB565 value.
port_map_t
GPIO/PORT block geometry (ra8_port_regs.h).
@ k_port_base
PORT0 base.
@ k_port_pcntr3
{PORR[31:16], POSR[15:0]} W.
@ k_port_span
Full PORT address window.
@ k_port_count
PORT0..PORT14.
@ k_port_pcntr4
{EORR[31:16], EOSR[15:0]} RW.
@ k_port_pcntr1
{PODR[31:16], PDR[15:0]} RW.
@ k_port_pcntr2
{EIDR[31:16], PIDR[15:0]} R.
@ k_port_stride
Bytes between adjacent ports.
static uint32_t s_led_level[k_board_led_count]
Last driven level.
led_color_t
RGB565 lit-colour codes for the three board LEDs.
@ k_led_rgb565_red
LED3 red (PA07) when driven high.
@ k_led_rgb565_blue
LED1 blue (P600) when driven high.
@ k_led_rgb565_green
LED2 green (P303) when driven high.
bool board_periph_gpio_get_input(uint8_t port, uint8_t pin)
Read the externally-injected input level of a GPIO pin.
void board_periph_gpio_set_input(uint8_t port, uint8_t pin, bool level)
Drive a GPIO pin's input level from outside the firmware.
sw_pin_t
EK-RA8D2 user-switch pins (PORT0): SW1=P009, SW2=P008 (UM Tbl 25).
@ k_sw1_pin
SW1 -> P009.
@ k_sw2_pin
SW2 -> P008.
@ k_sw_port
Both user switches are on PORT0.
static RA8_INTERNAL void internal_port_reset(void)
Clear every PORT latch / direction and the per-LED observability state.
Bounded raw-descriptor I/O seam for the RA8 emulator.
emu_io_result_t priv_emu_io_errf(const char *format,...)
Format bounded text and write it to the injected error descriptor.
-proof
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
ra8_board_eth_pin_t pin
Pin.
A modelled peripheral block's self-description for the core registry.
Board LED -> (port index, pin index, lit colour), from the BSP.
uint8_t port
Port.
uint16_t color
RGB565 colour the LED emits when driven high.
const char * name
Name.
uint8_t pin
Pin.
One PORT instance: direction + output latch (16 bits each).
uint16_t in_lvl
Driven input level for the in_ovr pins.
uint16_t pdr
Direction: 1 = output, 0 = input.
uint16_t in_ovr
Pins whose input level is externally driven.
uint16_t podr
Output-data latch.
static unsigned int internal_port_reset(void)
Pulse the root-hub port reset (assert then deassert).