ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
board_periph_adc.c
Go to the documentation of this file.
1
45
46#include <stdint.h>
47#include <stdio.h>
48
49#include "board_console.h"
50#include "board_periph_block.h"
52
54typedef enum : uint32_t {
57
59typedef enum : uint64_t {
60 k_adc_base = 0x40338000UL,
61 k_adc_span = 0x2224UL,
62 k_adc_off_adsger = 0x0048UL,
63 k_adc_off_adintcr = 0x005CUL,
64 k_adc_off_adsgdcr0 = 0x0200UL,
65 k_adc_off_adchcr0 = 0x0600UL,
67 k_adc_off_adtrgenr = 0x0C08UL,
68 k_adc_off_adstr0 = 0x0C20UL,
69 k_adc_off_adstopr = 0x0C60UL,
70 k_adc_off_adsr = 0x0C80UL,
71 k_adc_off_addr0 = 0x2000UL,
72 k_adc_off_adexdr0 = 0x2180UL,
78} adc_map_t;
79
81typedef enum : uint32_t {
86 k_adc_reg_words = 0x2224U / 4U,
87} adc_dim_t;
88
90typedef enum : uint32_t {
91 k_adc_adst_mask = 0x00000001UL,
92 k_adc_adact0_mask = 0x00000001UL,
93 k_adc_addr_data = 0x0000FFFFUL,
94 k_adc_chcr_sgsel = 0x0000001FUL,
95 k_adc_chcr_cnvcs_m = 0x00007F00UL,
97 k_adc_sgdcr_diagval = 0x00000007UL,
98 k_adc_opcrc_adprc_m = 0x00030000UL,
101
111typedef enum : uint32_t {
117
127typedef enum : uint16_t {
128 k_adc_mid_16bit = 0x8000U,
129 k_adc_mid_14bit = 0x2000U,
130 k_adc_mid_12bit = 0x0800U,
131 k_adc_mid_10bit = 0x0200U,
133
144typedef enum : uint32_t {
150
170
172typedef enum : uint16_t {
174 /* Temperature-sensor code: with the factory calibration ra8_emulator seeds at
175 * 0x02C1EDA0 (TSCDR=3000 @125C, TSCDR2=1000 @-40C), the two-point math in
176 * ra8_tsn_convert_to_milli_c maps this 12-bit code to ~26 degC -- a plausible,
177 * deterministic die temperature. See main.c k_tsn_cal_* for the paired seed. */
180
191typedef enum : uint16_t {
194
204static uint32_t s_adc_reg[k_adc_reg_words];
205static uint32_t s_adc_scans;
206static uint16_t s_adc_last_code;
207
219RA8_INTERNAL static uint32_t internal_adc_word(uint64_t off)
220{
221 return (uint32_t)(off >> 2U);
222}
223
235RA8_INTERNAL static uint32_t internal_adc_chcr(uint32_t ch)
236{
238 ((uint64_t)ch * (uint64_t)k_adc_chcr_stride))];
239}
240
251RA8_INTERNAL static void internal_adc_set_result(uint32_t ch, uint16_t code)
252{
253 if (ch >= (uint32_t)k_adc_result_regs) {
254 return;
255 }
256 const uint64_t off = (uint64_t)k_adc_off_addr0 + ((uint64_t)ch * (uint64_t)k_adc_addr_stride);
257 s_adc_reg[internal_adc_word(off)] = (uint32_t)code & (uint32_t)k_adc_addr_data;
258 s_adc_last_code = code;
259}
260
271RA8_INTERNAL static void internal_adc_set_ext_result(uint32_t idx, uint16_t code)
272{
273 if (idx >= (uint32_t)k_adc_ext_regs) {
274 return;
275 }
276 const uint64_t off = (uint64_t)k_adc_off_adexdr0 + ((uint64_t)idx * (uint64_t)k_adc_exdr_stride);
277 s_adc_reg[internal_adc_word(off)] = (uint32_t)code & (uint32_t)k_adc_addr_data;
278 s_adc_last_code = code;
279}
280
292RA8_INTERNAL static uint32_t internal_adc_diagval(uint32_t group)
293{
294 const uint64_t off =
295 (uint64_t)k_adc_off_adsgdcr0 + ((uint64_t)group * (uint64_t)k_adc_sgdcr_stride);
296 return s_adc_reg[internal_adc_word(off)] & (uint32_t)k_adc_sgdcr_diagval;
297}
298
310RA8_INTERNAL static uint16_t internal_adc_selfdiag_ideal(uint32_t diagval)
311{
312 switch (diagval) {
313 case (uint32_t)k_adc_diagval_mode2:
314 return (uint16_t)k_adc_selfdiag_negfs;
315 case (uint32_t)k_adc_diagval_mode3:
316 return (uint16_t)k_adc_selfdiag_posfs;
317 default:
318 return (uint16_t)k_adc_selfdiag_zero; /* mode 1 / DIAGVAL off. */
319 }
320}
321
334RA8_INTERNAL static uint16_t internal_adc_ext_value(uint32_t phys, uint32_t group)
335{
336 if (phys == (uint32_t)k_adc_chan_selfdiag) {
338 }
339 if (phys == (uint32_t)k_adc_chan_temp) {
340 return (uint16_t)k_adc_temp_code;
341 }
342 return (uint16_t)k_adc_sample_code; /* internal Vref + any other ext source. */
343}
344
356RA8_INTERNAL static uint32_t internal_adc_adprc(uint32_t slot)
357{
358 const uint64_t off =
359 (uint64_t)k_adc_off_addopcrc0 + ((uint64_t)slot * (uint64_t)k_adc_chcr_stride);
360 return (s_adc_reg[internal_adc_word(off)] & (uint32_t)k_adc_opcrc_adprc_m) >>
361 (uint32_t)k_adc_opcrc_adprc_s;
362}
363
375RA8_INTERNAL static uint16_t internal_adc_midscale_for_adprc(uint32_t adprc)
376{
377 switch (adprc) {
378 case (uint32_t)k_adc_adprc_16bit:
379 return (uint16_t)k_adc_mid_16bit;
380 case (uint32_t)k_adc_adprc_14bit:
381 return (uint16_t)k_adc_mid_14bit;
382 case (uint32_t)k_adc_adprc_10bit:
383 return (uint16_t)k_adc_mid_10bit;
384 default: /* 12-bit (0b10) and any unmodelled code. */
385 return (uint16_t)k_adc_mid_12bit;
386 }
387}
388
407RA8_INTERNAL static void internal_adc_convert_group(uint32_t group)
408{
409 uint32_t converted = 0U;
410 uint16_t last_code = 0U;
411 for (uint32_t slot = 0U; slot < (uint32_t)k_adc_max_channels; slot++) {
412 const uint32_t chcr = internal_adc_chcr(slot);
413 if ((chcr & (uint32_t)k_adc_chcr_sgsel) != group) {
414 continue;
415 }
416 const uint32_t phys = (chcr & (uint32_t)k_adc_chcr_cnvcs_m) >> (uint32_t)k_adc_chcr_cnvcs_s;
417 if (phys >= (uint32_t)k_adc_ext_chan_base) {
418 /* An internal / extended-analog channel (self-diagnosis, temperature
419 * sensor, internal Vref) reports through ADEXDR[CNVCS - base], not ADDR[]. */
420 last_code = internal_adc_ext_value(phys, group);
421 internal_adc_set_ext_result(phys - (uint32_t)k_adc_ext_chan_base, last_code);
422 converted++;
423 } else if (slot < (uint32_t)k_adc_result_regs) {
424 /* Normal channel -> its virtual-channel result register ADDR[slot].
425 * Resolution is the slot's ADDOPCRCn.ADPRC data-format, so a mid-scale
426 * input converts to that format's half-full-scale code. */
428 internal_adc_set_result(slot, last_code);
429 converted++;
430 }
431 /* else: a normal channel on a virtual slot with no ADDR result register
432 * (the diagnostic slot) produces no ordinary result. */
433 }
434 /* Console ADC tab: one line per scan-group conversion (coalesced -- a whole
435 * group is one push, never one per channel), skipped when the group is empty. */
436 if (converted != 0U) {
437 char ln[k_adc_console_line_cap];
438 (void)snprintf(ln,
439 sizeof(ln),
440 "ADC grp=%u %uch code=%u",
441 (unsigned)group,
442 (unsigned)converted,
443 (unsigned)last_code);
445 }
446}
447
461RA8_INTERNAL static uint64_t internal_adc_read(uc_engine* uc, uint64_t addr, unsigned size)
462{
463 (void)uc;
464 (void)size;
465 const uint64_t off = addr - (uint64_t)k_adc_base;
466 if (off == (uint64_t)k_adc_off_adsr) {
467 /* Conversion is modelled as instantaneous: ADACT0 reads idle so the
468 * driver's busy-poll completes on its first read and fetches ADDR. */
469 return s_adc_reg[internal_adc_word(off)] & ~(uint32_t)k_adc_adact0_mask;
470 }
471 if (off >= (uint64_t)k_adc_span) {
472 return 0U;
473 }
474 return s_adc_reg[internal_adc_word(off)];
475}
476
489RA8_INTERNAL static void
490internal_adc_write(uc_engine* uc, uint64_t addr, unsigned size, uint64_t value)
491{
492 (void)size;
493 const uint64_t off = addr - (uint64_t)k_adc_base;
494 if (off >= (uint64_t)k_adc_span) {
495 return;
496 }
497 const uint64_t str_lo = (uint64_t)k_adc_off_adstr0;
498 const uint64_t str_hi = str_lo + ((uint64_t)k_adc_scan_groups * (uint64_t)k_adc_str_stride);
499 if ((off >= str_lo) && (off < str_hi) && ((value & (uint64_t)k_adc_adst_mask) != 0U)) {
500 const uint32_t group = (uint32_t)((off - str_lo) / (uint64_t)k_adc_str_stride);
501 s_adc_reg[internal_adc_word(off)] = (uint32_t)value;
503 s_adc_scans++;
505 if (board_periph_trace()) {
506 (void)priv_emu_io_errf(" [trace] ADC_B scan grp%u -> code=%u\n",
507 group,
508 (unsigned)s_adc_last_code);
509 }
510 return;
511 }
512 s_adc_reg[internal_adc_word(off)] = (uint32_t)value;
513}
514
524{
525 for (uint32_t i = 0U; i < (uint32_t)k_adc_reg_words; i++) {
526 s_adc_reg[i] = 0U;
527 }
528 s_adc_scans = 0U;
529 s_adc_last_code = 0U;
530}
531
541{
542 if (s_adc_scans == 0U) {
543 return;
544 }
545 (void)priv_emu_io_errf(" ADC_B : scans=%u last_code=%u (0x%03X)\n",
549}
550
553 .base = (uint64_t)k_adc_base,
554 .span = (uint64_t)k_adc_span,
555 .order = (uint32_t)k_block_order_i2c, /* After the timers/UART; no tick. */
556 .read = internal_adc_read,
558 .tick = nullptr,
559 .reset = internal_adc_reset,
560 .report = internal_adc_report,
561 .name = "ADC_B",
562};
563
565[[gnu::constructor]] RA8_INTERNAL static void internal_board_periph_adc_register(void)
566{
568}
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_adc
ADC_B conversion summaries.
static RA8_INTERNAL uint16_t internal_adc_midscale_for_adprc(uint32_t adprc)
Resolution-appropriate mid-scale result code for an ADPRC format.
adc_elc_event_t
ADC_B scan-complete (ADI) ELC event the model raises on a scan start.
@ k_event_adc0_scan_end
ADC0 ADI scan-complete event.
adc_map_t
ADC_B block geometry (ra8_adc_b_regs.h, FSP R_ADC_B0_Type).
@ k_adc_sgdcr_stride
ADSGDCRn is 4 bytes per slot.
@ k_adc_str_stride
ADSTR[n] is 4 bytes per slot.
@ k_adc_chcr_stride
ADCHCRn occupies 16 bytes per slot.
@ k_adc_span
Full FSP R_ADC_B0_Type window size.
@ k_adc_off_adsger
ADSGER scan-group enable.
@ k_adc_off_adexdr0
ADEXDR[0] extended-analog results.
@ k_adc_off_addopcrc0
ADDOPCRC[0] per-channel ADPRC format.
@ k_adc_off_adsgdcr0
ADSGDCR[0] scan-group self-diag ctrl.
@ k_adc_off_adstr0
ADSTR[0] per-group SW start.
@ k_adc_off_adsr
ADSR conversion status (RO).
@ k_adc_off_adchcr0
ADCHCR[0] per-channel config.
@ k_adc_off_adstopr
ADSTOPR force-stop.
@ k_adc_off_adtrgenr
ADTRGENR per-group HW-trigger enable.
@ k_adc_exdr_stride
ADEXDRn is 4 bytes per slot.
@ k_adc_off_adintcr
ADINTCR per-group scan-end IE.
@ k_adc_base
ADC_B register-window base.
@ k_adc_off_addr0
ADDR[0] conversion results.
@ k_adc_addr_stride
ADDR[n] is 4 bytes per slot.
static RA8_INTERNAL uint32_t internal_adc_diagval(uint32_t group)
Read ADSGDCR[group].DIAGVAL[2:0] (self-diagnosis mode) from the store.
static RA8_INTERNAL void internal_adc_reset(void)
Clear all ADC_B register state and observability counters.
static RA8_INTERNAL uint64_t internal_adc_read(uc_engine *uc, uint64_t addr, unsigned size)
MMIO read: ADSR holds ADACT0 idle; everything else reads back.
static uint16_t s_adc_last_code
Last result code written to an ADDR.
adc_ext_chan_t
Extended-analog (internal) channel CNVCS codes (ra8_adc_b_regs.h).
@ k_adc_chan_selfdiag
Self-diagnosis A/D unit 0.
@ k_adc_chan_temp
On-chip temperature sensor.
@ k_adc_chan_int_vref
Internal reference voltage.
@ k_adc_ext_chan_base
ADEXDR index origin (n = CNVCS - base).
static RA8_INTERNAL void internal_adc_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value)
MMIO write: ADSTR kicks a scan; other registers latch the value.
static RA8_INTERNAL void internal_adc_convert_group(uint32_t group)
Populate result registers for every channel enrolled in group.
static RA8_INTERNAL uint32_t internal_adc_chcr(uint32_t ch)
Read an ADCHCRn slot's raw config word from the backing store.
adc_field_t
ADC_B field shifts / masks the model consults.
@ k_adc_chcr_cnvcs_s
ADCHCRn.CNVCS shift.
@ k_adc_sgdcr_diagval
ADSGDCRn.DIAGVAL[2:0] mode.
@ k_adc_opcrc_adprc_s
ADDOPCRCn.ADPRC shift.
@ k_adc_adst_mask
ADSTR[n].ADST start bit.
@ k_adc_addr_data
ADDR[n] DATA[15:0] field.
@ k_adc_adact0_mask
ADSR.ADACT0 unit-0 busy flag.
@ k_adc_opcrc_adprc_m
ADDOPCRCn.ADPRC[17:16] format.
@ k_adc_chcr_cnvcs_m
ADCHCRn.CNVCS[14:8] phys channel.
@ k_adc_chcr_sgsel
ADCHCRn.SGSEL[4:0] scan group.
adc_console_t
Console-tap line buffer capacity for an ADC conversion summary.
@ k_adc_console_line_cap
Max chars in an "ADC grp=.. .." line.
static RA8_INTERNAL uint32_t internal_adc_word(uint64_t off)
Word index into the backing store for an in-window offset.
static RA8_INTERNAL uint16_t internal_adc_selfdiag_ideal(uint32_t diagval)
Ideal 16-bit self-diagnosis code for the armed DIAGVAL mode.
static RA8_INTERNAL void internal_adc_report(void)
Print the ADC_B scan count + last reported result code.
static RA8_INTERNAL void internal_board_periph_adc_register(void)
Self-register the ADC_B block before main runs (decentralized).
static const board_periph_block_t s_k_adc_block
This block's descriptor (static lifetime; the core keeps the pointer).
adc_midscale_t
Resolution-appropriate mid-scale (half-full-scale) result codes.
@ k_adc_mid_16bit
16-bit half-scale.
@ k_adc_mid_12bit
12-bit half-scale.
@ k_adc_mid_14bit
14-bit half-scale.
@ k_adc_mid_10bit
10-bit half-scale.
static RA8_INTERNAL uint32_t internal_adc_adprc(uint32_t slot)
Read ADDOPCRC[slot].ADPRC[1:0] data-format code from the store.
adc_adprc_t
ADDOPCRCn.ADPRC[1:0] data-format codes (HUM Ch 53.2.3.4 p 3339).
@ k_adc_adprc_10bit
ADPRC 0b11: 10-bit result.
@ k_adc_adprc_16bit
ADPRC 0b00: 16-bit result.
@ k_adc_adprc_14bit
ADPRC 0b01: 14-bit result.
@ k_adc_adprc_12bit
ADPRC 0b10: 12-bit result.
static RA8_INTERNAL void internal_adc_set_ext_result(uint32_t idx, uint16_t code)
Store an extended-analog result into ADEXDR[idx] (DATA[15:0], ERR clear).
adc_selfdiag_t
ADSGDCRn.DIAGVAL self-diagnosis mode codes + ideal 16-bit results.
@ k_adc_diagval_mode1
DIAGVAL mode 1: zero.
@ k_adc_selfdiag_posfs
Mode-3 ideal 0x7FFF (+32767).
@ k_adc_selfdiag_negfs
Mode-2 ideal 0x8000 (-32768).
@ k_adc_diagval_mode3
DIAGVAL mode 3: positive full-scale.
@ k_adc_selfdiag_zero
Mode-1 ideal 0x0000.
@ k_adc_diagval_mode2
DIAGVAL mode 2: negative full-scale.
adc_sample_t
Plausible conversion result reported on every scan.
@ k_adc_temp_code
12-bit temperature-sensor code (~26 degC).
@ k_adc_sample_code
12-bit half-scale (~VREFH/2) mid-scale.
static uint32_t s_adc_reg[k_adc_reg_words]
Backing store for the whole ADC_B window (word-addressed).
static RA8_INTERNAL uint16_t internal_adc_ext_value(uint32_t phys, uint32_t group)
Synthetic ADEXDR code for an extended-analog channel (phys >= base).
static RA8_INTERNAL void internal_adc_set_result(uint32_t ch, uint16_t code)
Store a freshly converted code into ADDR[ch] (DATA[15:0], ERR clear).
static uint32_t s_adc_scans
Conversions kicked via ADSTR.
adc_dim_t
ADC_B array dimensions (mirror ra8_adc_b_limits_t).
@ k_adc_reg_words
Backing-store word count.
@ k_adc_max_channels
ADCHCR0..23 virtual-channel config slots.
@ k_adc_ext_regs
ADEXDR[0..22] extended-analog slots.
@ k_adc_result_regs
ADDR[0..22] result slots.
@ k_adc_scan_groups
ADSGER / ADTRGENR / ADSTR width [8:0].
Decentralized peripheral-block registry for the board emulator core.
void board_periph_icu_raise_event(uc_engine *uc, uint16_t event)
Raise a peripheral ELC event through the core's ICU -> NVIC path.
void board_periph_register_block(const board_periph_block_t *block)
Register a peripheral block's descriptor with the core registry.
@ k_block_order_i2c
I3C/I2C + GT911 (no tick today).
bool board_periph_trace(void)
Whether –trace is active (blocks log transitions when true).
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).
A modelled peripheral block's self-description for the core registry.