ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_lvd_runtime.c
Go to the documentation of this file.
1
21
22#include <stdint.h>
23
24#include "ra8_check.h"
25#include "ra8_err.h"
26#include "ra8_lvd.h"
27#include "ra8_lvd_internal.h"
28#include "ra8_lvd_regs.h"
29
39static const char* s_tag = "LVD";
40
41/* =============================================================================
42 * IRQ / reset / CMPE single-bit toggles
43 * =============================================================================
44 */
45
69{
70 uint8_t idx = 0U;
71 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
72 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_enable_irq: bad channel");
73
74 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
75 if (!map.has_irq) {
77 }
78 /* set RIE. */
79 /* HUM Ch 8.2.4 "PVDmCR0 : Voltage Monitor m Circuit Control Register 0" p 305 */
81 return k_ra8_ok;
82}
83
107{
108 uint8_t idx = 0U;
109 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
110 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_disable_irq: bad channel");
111
112 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
113 if (!map.has_irq) {
115 }
116 /* HUM Ch 8.2.4 "PVDmCR0" p 305 */
118 return k_ra8_ok;
119}
120
143{
144 uint8_t idx = 0U;
145 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
146 /* GCOVR_EXCL_BR_START -- channel_to_idx() error edge; enable_reset pre-validates the channel */
147 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_enable_reset: bad channel");
148 /* GCOVR_EXCL_BR_STOP */
149
150 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
151 if (map.has_irq) {
152 /* m channel: set RI then RIE. */
153 /* HUM Ch 8.2.4 "PVDmCR0" p 305 */
155 0U,
157 } else {
158 /* n channel: set RE only -- it is the only response option. */
159 /* HUM Ch 8.2.5 "PVDnCR0" p 306 */
161 }
162 return k_ra8_ok;
163}
164
187{
188 uint8_t idx = 0U;
189 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
190 /* GCOVR_EXCL_BR_START -- channel_to_idx() error edge; disable_reset pre-validates the channel */
191 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_disable_reset: bad channel");
192 /* GCOVR_EXCL_BR_STOP */
193
194 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
195 /* HUM Ch 8.2.4 "PVDmCR0" p 305 */
196 uint8_t enable_bit = k_ra8_lvd_cr0_mask_re;
197 if (map.has_irq) {
198 enable_bit = k_ra8_lvd_cr0_mask_rie;
199 }
200 priv_ra8_lvd_internal_cr0_rmw(&map, enable_bit, 0U);
201 return k_ra8_ok;
202}
203
227{
228 uint8_t idx = 0U;
229 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
230 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_enable_cmpe: bad channel");
231
232 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
233 /* HUM Ch 8.2.4 "PVDmCR0" p 305 */
235 return k_ra8_ok;
236}
237
260{
261 uint8_t idx = 0U;
262 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
263 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_disable_cmpe: bad channel");
264
265 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
266 /* HUM Ch 8.2.4 "PVDmCR0" p 305 */
268 return k_ra8_ok;
269}
270
271/* =============================================================================
272 * Filter + RHSEL + RN runtime updates
273 * =============================================================================
274 */
275
301ra8_lvd_set_filter(ra8_lvd_channel_t channel, ra8_lvd_loco_div_t filter_div, bool filter_en)
302{
303 uint8_t idx = 0U;
304 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
305 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_set_filter: bad channel");
306
307 const ra8_err_t div_err = priv_ra8_lvd_internal_validate_div(filter_div);
308 RA8_RETURN_ON_ERROR(div_err, s_tag, "lvd_set_filter: bad div");
309
310 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
311
312 /* HUM Ch 8.2.4 "PVDmCR0" p 305 / HUM Ch 8.2.5 "PVDnCR0" p 306
313 * -- FSAMP can only be modified while DFDIS = 1. */
315
316 const uint8_t fsamp_bits =
317 (uint8_t)(((uint8_t)filter_div << k_ra8_lvd_cr0_shift_fsamp) & k_ra8_lvd_cr0_mask_fsamp);
319
320 if (filter_en) {
321 /* Drop DFDIS only after FSAMP has landed. */
323 }
324 return k_ra8_ok;
325}
326
353{
354 uint8_t idx = 0U;
355 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
356 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_set_hysteresis_mode: bad channel");
357
358 if ((uint8_t)hyst > k_ra8_lvd_hysteresis_hvd) {
360 }
361
362 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
363
364 /* HUM Ch 8.2.8 "PVDmFCR" p 308 last bullet -- "RHSEL must not be set
365 * to 1 when PVDmCR0.RI = 0." Enforce only on m channels (n channels
366 * have no RI bit; their RHSEL is always legal). */
367 if (map.has_irq && (hyst == k_ra8_lvd_hysteresis_hvd)) {
368 if (priv_ra8_lvd_internal_read_ri(&map) == 0U) {
370 }
371 }
372
373 /* HUM Ch 8.2.8 / 8.2.9 -- RHSEL can only be modified when every
374 * PVDE is 0; preserve and restore this channel's PVDE. */
375 const uint8_t prev_cmpcr = *ra8_lvd_reg8(map.cmpcr);
376 const uint8_t pvde_was = (uint8_t)(prev_cmpcr & k_ra8_lvd_cmpcr_mask_pvde);
377 *ra8_lvd_reg8(map.cmpcr) = (uint8_t)(prev_cmpcr & (uint8_t)~k_ra8_lvd_cmpcr_mask_pvde);
378
379 /* HUM Ch 8.2.8 "PVDmFCR" p 308 */
380 *ra8_lvd_reg8(map.fcr) = (uint8_t)((uint8_t)hyst & k_ra8_lvd_fcr_mask_rhsel);
381
382 /* Restore PVDE if it had been set. */
383 *ra8_lvd_reg8(map.cmpcr) = (uint8_t)(*ra8_lvd_reg8(map.cmpcr) | pvde_was);
384 return k_ra8_ok;
385}
386
412{
413 uint8_t idx = 0U;
414 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
415 /* GCOVR_EXCL_BR_START -- channel_to_idx() error edge; set_negate_mode pre-validates it */
416 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_set_negate_mode: bad channel");
417 /* GCOVR_EXCL_BR_STOP */
418
419 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
420 if (!map.has_irq) {
422 }
423 if ((uint8_t)negate > k_ra8_lvd_negate_after_assert) {
425 }
426
427 /* HUM Ch 8.2.4 "PVDmCR0" p 306 */
428 /* HUM Ch 8.2.8 "PVDmFCR" p 308 */
429 if (negate == k_ra8_lvd_negate_after_assert) {
430 const uint8_t fcr = *ra8_lvd_reg8(map.fcr);
431 if ((fcr & k_ra8_lvd_fcr_mask_rhsel) != 0U) {
433 }
434 }
435
436 /* HUM Ch 8.2.4 "PVDmCR0" p 305 */
440 : 0U);
441 return k_ra8_ok;
442}
443
444/* =============================================================================
445 * Status read / clear
446 * =============================================================================
447 */
448
475{
476 RA8_CHECK_NULL_PTR(out, s_tag, "out must not be nullptr");
477
478 uint8_t idx = 0U;
479 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
480 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_get_status: bad channel");
481
482 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
483 if (!map.has_irq) {
485 }
486
487 /* HUM Ch 8.2.7 "PVDmSR : Voltage Monitor m Circuit Status Register" p 307 */
488 const uint8_t sr = *ra8_lvd_reg8(map.sr);
489 out->crossed = ((sr & k_ra8_lvd_sr_mask_det) != 0U);
490 out->above = ((sr & k_ra8_lvd_sr_mask_mon) != 0U);
491 return k_ra8_ok;
492}
493
517{
518 uint8_t idx = 0U;
519 const ra8_err_t map_err = priv_ra8_lvd_internal_channel_to_idx(channel, &idx);
520 RA8_RETURN_ON_ERROR(map_err, s_tag, "lvd_clear_status: bad channel");
521
522 const ra8_lvd_channel_map_t map = g_lvd_map[idx];
523 if (!map.has_irq) {
525 }
526
527 /* HUM Ch 8.2.7 "PVDmSR : Voltage Monitor m Circuit Status Register" p 307
528 * Note 1 -- only 0 can be written to DET. MON is preserved by
529 * clearing only the DET bit. */
530 const uint8_t sr = *ra8_lvd_reg8(map.sr);
531 const uint8_t next = (uint8_t)(sr & (uint8_t)~k_ra8_lvd_sr_mask_det);
532 *ra8_lvd_reg8(map.sr) = next;
533 return k_ra8_ok;
534}
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
#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_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_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
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
ra8_err_t priv_ra8_lvd_internal_validate_div(ra8_lvd_loco_div_t div)
Implementation of priv_ra8_lvd_internal_validate_div() – upper-bound check.
Definition ra8_lvd.c:194
uint8_t priv_ra8_lvd_internal_read_ri(const ra8_lvd_channel_map_t *map)
Implementation of priv_ra8_lvd_internal_read_ri() – masked CR0 read.
Definition ra8_lvd.c:233
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.
Test-access surface for ra8_lvd internal helpers (MC/DC).
Programmable Voltage Detection (PVD / LVD) register layout for the RA8D2.
@ k_ra8_lvd_sr_mask_det
DET latched-crossing flag.
@ k_ra8_lvd_sr_mask_mon
MON live above-threshold flag.
@ k_ra8_lvd_cr0_mask_re
RE (n) – reset-only enable.
@ 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_rie
RIE (m) – IRQ/reset enable.
@ k_ra8_lvd_cr0_mask_dfdis
DFDIS digital-filter disable.
@ k_ra8_lvd_cr0_mask_fsamp
FSAMP[1:0] divider field.
static volatile uint8_t * ra8_lvd_reg8(ra8_lvd_off_t off)
Get a volatile uint8_t* to a PVD 8-bit register.
@ k_ra8_lvd_cmpcr_mask_pvde
PVDE detector enable.
@ k_ra8_lvd_fcr_mask_rhsel
RHSEL hysteresis-band selector.
@ k_ra8_lvd_cr0_shift_fsamp
FSAMP[1:0] starts at bit 4.
ra8_err_t ra8_lvd_enable_cmpe(ra8_lvd_channel_t channel)
Set CR0.CMPE so the comparator output drives the response logic.
ra8_err_t ra8_lvd_clear_status(ra8_lvd_channel_t channel)
Acknowledge PVDmSR.DET via write-0-to-clear.
ra8_err_t ra8_lvd_disable_reset(ra8_lvd_channel_t channel)
Disarm the reset response for a PVD channel.
ra8_err_t ra8_lvd_get_status(ra8_lvd_channel_t channel, ra8_lvd_status_t *out)
Read PVDmSR and decode DET / MON into ra8_lvd_status_t.
ra8_err_t ra8_lvd_enable_irq(ra8_lvd_channel_t channel)
Set CR0.RIE on an IRQ-capable PVDm channel.
ra8_err_t ra8_lvd_set_negate_mode(ra8_lvd_channel_t channel, ra8_lvd_negate_t negate)
Update CR0.RN (negate-after-assert) for a PVDm channel.
ra8_err_t ra8_lvd_set_filter(ra8_lvd_channel_t channel, ra8_lvd_loco_div_t filter_div, bool filter_en)
Update FSAMP and DFDIS for a PVD channel at runtime.
ra8_err_t ra8_lvd_disable_irq(ra8_lvd_channel_t channel)
Clear CR0.RIE on an IRQ-capable PVDm channel.
ra8_err_t ra8_lvd_enable_reset(ra8_lvd_channel_t channel)
Arm the reset response for a PVD channel.
ra8_err_t ra8_lvd_set_hysteresis_mode(ra8_lvd_channel_t channel, ra8_lvd_hysteresis_t hyst)
Update FCR.RHSEL (hysteresis mode) for a PVD channel.
ra8_err_t ra8_lvd_disable_cmpe(ra8_lvd_channel_t channel)
Clear CR0.CMPE so the comparator stops driving the response logic.
ra8_lvd_loco_div_t
PVDmCR0.FSAMP[1:0] / PVDnCR0.FSAMP[1:0] sampling-clock divider.
ra8_lvd_negate_t
PVDmCR0.RN value – reset deassertion timing.
@ k_ra8_lvd_negate_after_assert
Negate after reset asserts.
ra8_lvd_hysteresis_t
PVDmFCR.RHSEL / PVDnFCR.RHSEL value.
@ k_ra8_lvd_hysteresis_hvd
RHSEL = 1 (rise detect).
ra8_lvd_channel_t
Voltage-monitor channel selector.
Per-channel register-offset bundle.
ra8_lvd_off_t fcr
PVDxFCR (RHSEL).
ra8_lvd_off_t cmpcr
PVDxCMPCR offset.
ra8_lvd_off_t sr
PVDxSR (m only; n: same as cr0 stub).
bool has_irq
true for monitor m channels (1, 2).
Decoded PVDmSR snapshot.
bool crossed
DET flag: a Vdetm crossing was latched.
bool above
MON flag: VCC currently above Vdetm threshold.