ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_lvd_events.c
Go to the documentation of this file.
1
23
24#include <stdint.h>
25
26#include "ra8_check.h"
27#include "ra8_err.h"
28#include "ra8_lvd.h"
29#include "ra8_lvd_internal.h"
30#include "ra8_lvd_regs.h"
31
41static const char* s_tag = "LVD";
42
43/* =============================================================================
44 * Callback storage
45 * =============================================================================
46 */
47
53
58static void* s_lvd_ctx;
59
70
76
77/* =============================================================================
78 * Security attribution + n-channel lock
79 * =============================================================================
80 */
81
104{
105 /* HUM Ch 8.2.1 "PVDSAR : Programmable Voltage Detection Security
106 * Attribution Register" p 302 */
107 if ((mask & ~k_ra8_lvd_pvdsar_mask_all) != 0U) {
109 }
111 return k_ra8_ok;
112}
113
134{
135 /* HUM Ch 8.2.10 "PVDLR : Voltage Monitor Lock Register" p 309 */
137 return k_ra8_ok;
138}
139
160{
161 /* HUM Ch 8.2.10 "PVDLR : Voltage Monitor Lock Register" p 309 --
162 * "if you write an arbitrary value to the LOCK, the LOCK bit is
163 * fixed to 1." */
165 return k_ra8_ok;
166}
167
168/* =============================================================================
169 * ELC + standby helpers
170 * =============================================================================
171 */
172
197{
198 uint8_t idx = 0U;
199 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
200 /* GCOVR_EXCL_BR_START -- channel_to_idx() error edge; enable_elc_event pre-validates it */
201 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_enable_elc_event: bad channel");
202 /* GCOVR_EXCL_BR_STOP */
203
204 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
205 if (!map.has_irq) {
207 }
208
209 /* HUM Ch 8.7 "Event Link Controller (ELC) Output" p 315 -- the event
210 * line tracks the comparator output enable: clear DET first, then
211 * raise CMPE. */
212 /* HUM Ch 8.2.7 "PVDmSR : Voltage Monitor m Circuit Status Register" p 307 */
213 const uint8_t sr = *ra8_lvd_reg8(map.sr);
214 *ra8_lvd_reg8(map.sr) = (uint8_t)(sr & (uint8_t)~k_ra8_lvd_sr_mask_det);
215 /* HUM Ch 8.2.4 "PVDmCR0" p 305 */
217 return k_ra8_ok;
218}
219
242{
243 uint8_t idx = 0U;
244 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
245 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_disable_elc_event: bad channel");
246
247 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
248 if (!map.has_irq) {
250 }
251 /* HUM Ch 8.2.4 "PVDmCR0" p 305 -- clear CMPE so the ELC line goes
252 * inactive (HUM 8.7 p 315). */
254 return k_ra8_ok;
255}
256
279{
280 uint8_t idx = 0U;
281 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
282 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_configure_for_standby: bad channel");
283
284 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
285
286 /* HUM Ch 8.5(1) "Setting in Software Standby mode" p 311 +
287 * HUM Ch 8.5(2) "Settings in Deep Software Standby mode" p 312 --
288 * disable the digital filter and (for m channels) clear RI + RN. */
289 uint8_t set_bits = k_ra8_lvd_cr0_mask_dfdis;
290 uint8_t clr_bits = 0U;
291 if (map.has_irq) {
292 clr_bits |= k_ra8_lvd_cr0_mask_ri;
293 clr_bits |= k_ra8_lvd_cr0_mask_rn;
294 }
295 /* HUM Ch 8.2.4 "PVDmCR0" p 305 */
296 priv_ra8_lvd_internal_cr0_rmw(&map, clr_bits, set_bits);
297 return k_ra8_ok;
298}
299
320{
321 /* HUM Ch 8.2.4 "PVDmCR0" p 305 */
322 for (uint8_t i = 0U; i < k_ra8_lvd_nmi_channel_count; ++i) {
324 }
325 return k_ra8_ok;
326}
327
328/* =============================================================================
329 * Filter timing helper (pure)
330 * =============================================================================
331 */
332
355uint32_t ra8_lvd_filter_delay_us(ra8_lvd_loco_div_t div, uint32_t loco_hz)
356{
357 /* HUM Table 8.4 step 8 (p 312) / Table 8.6 step 8 (p 315): wait for
358 * "2s + 3 cycles of the LOCO" where s = 2^(div+1). */
359 uint8_t safe_div = (uint8_t)div;
360 if (safe_div > k_ra8_lvd_loco_div_max) {
361 safe_div = k_ra8_lvd_loco_div_max;
362 }
363 const uint32_t local_factor = (uint32_t)1U << (safe_div + 1U);
364 const uint32_t loco_cycles = (k_ra8_lvd_filter_factor * local_factor) + k_ra8_lvd_filter_extra;
365 const uint32_t hz = (loco_hz != 0U) ? loco_hz : k_ra8_lvd_loco_hz_default;
366 /* +1 us round-up matches FSP's r_lvd_filter_delay computation. */
367 return ((loco_cycles * k_ra8_lvd_us_per_sec) / hz) + 1U;
368}
369
370/* =============================================================================
371 * Callback registration + ISR demux
372 * =============================================================================
373 */
374
397{
398 s_lvd_fn = fn;
399 s_lvd_ctx = ctx;
400 return k_ra8_ok;
401}
402
429{
430 uint8_t idx = 0U;
431 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
432 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_attach_channel_handler: bad channel");
433
434 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
435 if (!map.has_irq) {
437 }
438 s_lvd_chan_fn[idx] = fn;
439 s_lvd_chan_ctx[idx] = ctx;
440 return k_ra8_ok;
441}
442
464{
465 uint8_t idx = 0U;
466 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
467 if (map_err != k_ra8_ok) {
468 return;
469 }
470 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
471
472 /* Only m channels have a status register / IRQ path. */
473 if (!map.has_irq) {
474 return;
475 }
476
477 /* HUM Ch 8.2.7 "PVDmSR : Voltage Monitor m Circuit Status Register" p 307
478 * -- only fire the callback if a crossing was actually latched. */
479 const uint8_t sr = *ra8_lvd_reg8(map.sr);
480 if ((sr & k_ra8_lvd_sr_mask_det) == 0U) {
481 return;
482 }
483
484 /* Per-channel callback wins; otherwise fall back to the shared one. */
485 const ra8_lvd_event_fn_t chan_fn = s_lvd_chan_fn[idx];
486 void* const chan_ctx = s_lvd_chan_ctx[idx];
487 const ra8_lvd_event_fn_t fn = (chan_fn != nullptr) ? chan_fn : s_lvd_fn;
488 void* const ctx = (chan_fn != nullptr) ? chan_ctx : s_lvd_ctx;
489 if (fn != nullptr) {
490 fn(ctx, channel);
491 }
492
493 /* Write 0 to DET so the next crossing can latch (HUM 8.2.7 Note 1 p 307). */
494 const uint8_t cleared = (uint8_t)(*ra8_lvd_reg8(map.sr) & (uint8_t)~k_ra8_lvd_sr_mask_det);
495 *ra8_lvd_reg8(map.sr) = cleared;
496}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
Error Code Definitions for ra8-firmware.
@ k_ra8_err_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
Definition ra8_err.h:180
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ 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
const ra8_lvd_channel_map_t g_lvd_map[k_ra8_lvd_map_idx_count]
Lookup table from ra8_lvd_map_idx_t to register offsets.
Definition ra8_lvd.c:108
ra8_err_t priv_ra8_lvd_internal_channel_to_idx(ra8_lvd_channel_t channel, uint8_t *out_idx)
Implementation of priv_ra8_lvd_internal_channel_to_idx() – switch on PVD id.
Definition ra8_lvd.c:141
void priv_ra8_lvd_internal_cr0_rmw(const ra8_lvd_channel_map_t *map, uint8_t clear_mask, uint8_t set_bits)
Implementation of priv_ra8_lvd_internal_cr0_rmw() – RMW with reserved-bit refold.
Definition ra8_lvd.c:325
Programmable Voltage Detection (PVD / LVD) HAL driver.
ra8_err_t ra8_lvd_disable_elc_event(ra8_lvd_channel_t channel)
Disarm the ELC event line for a PVDm channel.
ra8_err_t ra8_lvd_cancel_deep_standby_path(void)
Drop CR0.RI on every NMI-capable channel (deep-standby exit).
ra8_err_t ra8_lvd_attach_channel_handler(ra8_lvd_channel_t channel, ra8_lvd_event_fn_t fn, void *ctx)
Register a per-channel LVD callback for a PVDm channel.
static ra8_lvd_event_fn_t s_lvd_fn
Shared crossing callback (set via ra8_lvd_attach_handler).
ra8_err_t ra8_lvd_relock_n_channels(void)
Relock PVDLR after a PVDn maintenance window.
ra8_err_t ra8_lvd_configure_for_standby(ra8_lvd_channel_t channel)
Reconfigure a PVD channel for entry into Software / Deep Standby.
uint32_t ra8_lvd_filter_delay_us(ra8_lvd_loco_div_t div, uint32_t loco_hz)
Compute the digital-filter settle delay in microseconds.
void ra8_lvd_dispatch(ra8_lvd_channel_t channel)
Demux a PVD ISR – ack DET, fire per-channel + shared callbacks.
static void * s_lvd_chan_ctx[k_ra8_lvd_map_idx_count]
Per-channel callback contexts paired with s_lvd_chan_fn.
static ra8_lvd_event_fn_t s_lvd_chan_fn[k_ra8_lvd_map_idx_count]
Per-channel override callbacks for PVD1 / PVD2.
ra8_err_t ra8_lvd_set_security(uint32_t mask)
Program PVDSAR security attribution for PVD channels.
ra8_err_t ra8_lvd_enable_elc_event(ra8_lvd_channel_t channel)
Arm the ELC event line for a PVDm channel.
static void * s_lvd_ctx
Context passed to s_lvd_fn.
ra8_err_t ra8_lvd_attach_handler(ra8_lvd_event_fn_t fn, void *ctx)
Register the shared LVD ISR callback (NULL detaches).
ra8_err_t ra8_lvd_unlock_n_channels(void)
Unlock PVDLR so PVDn channels accept further writes.
Test-access surface for ra8_lvd internal helpers (MC/DC).
@ k_ra8_lvd_map_idx_count
Sentinel.
Programmable Voltage Detection (PVD / LVD) register layout for the RA8D2.
@ k_ra8_lvd_sr_mask_det
DET latched-crossing flag.
@ k_ra8_lvd_pvdlr_value_unlock
Write 0 to release lock.
@ k_ra8_lvd_pvdlr_value_relock
Any nonzero re-locks forever.
@ k_ra8_lvd_filter_extra
"+3" LOCO cycles in HUM formula.
@ k_ra8_lvd_us_per_sec
Microseconds per second.
@ k_ra8_lvd_filter_factor
"2s" multiplier in HUM formula.
@ k_ra8_lvd_loco_hz_default
Nominal RA8D2 LOCO frequency.
@ k_ra8_lvd_cr0_mask_rn
RN reset-negate timing (m).
@ k_ra8_lvd_cr0_mask_cmpe
CMPE comparator-output enable.
@ k_ra8_lvd_cr0_mask_ri
RI reset-on-cross select (m).
@ k_ra8_lvd_cr0_mask_dfdis
DFDIS digital-filter disable.
@ k_ra8_lvd_pvdsar_mask_all
Both PVD1 + PVD2 NS.
static volatile uint8_t * ra8_lvd_reg8(ra8_lvd_off_t off)
Get a volatile uint8_t* to a PVD 8-bit register.
static volatile uint32_t * ra8_lvd_reg32(ra8_lvd_off_t off)
Get a volatile uint32_t* to a PVD 32-bit register.
@ k_ra8_lvd_nmi_channel_count
PVD1 + PVD2 (m channels).
@ k_ra8_lvd_pvdlr_off
PVDLR.
@ k_ra8_lvd_pvdsar_off
PVDSAR.
ra8_lvd_loco_div_t
PVDmCR0.FSAMP[1:0] / PVDnCR0.FSAMP[1:0] sampling-clock divider.
@ k_ra8_lvd_loco_div_max
Highest legal value (sentinel).
void(* ra8_lvd_event_fn_t)(void *ctx, ra8_lvd_channel_t channel)
PVD threshold-crossing callback.
ra8_lvd_channel_t
Voltage-monitor channel selector.
Per-channel register-offset bundle.
ra8_lvd_off_t sr
PVDxSR (m only; n: same as cr0 stub).
bool has_irq
true for monitor m channels (1, 2).