ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1
40
41#include <stdint.h>
42
43#include "ra8_audio.h"
45#include "ra8_board_ek_ra8d2.h"
46#include "ra8_boot_entry.h"
47#include "ra8_err.h"
48#include "ra8_mstp.h"
49#include "ra8_time.h"
50
51/* =============================================================================
52 * App-wide tunables
53 * =============================================================================
54 */
55
66
72
74typedef enum : uint32_t {
77
79typedef enum : uint32_t {
83
84/* =============================================================================
85 * Captured-window metrics + J-Link-probable result
86 * =============================================================================
87 */
88
93typedef struct {
94 int32_t min;
95 int32_t max;
96 int32_t mean;
97 int32_t peak;
98 int32_t rms;
99 uint32_t n;
101
108typedef struct {
109 volatile uint32_t magic;
110 volatile int32_t rms;
111 volatile int32_t peak;
112 volatile int32_t mean;
113 volatile int32_t span;
114 volatile int32_t vary;
115 volatile uint32_t samples;
116 volatile uint32_t active;
117 volatile uint32_t windows;
119 volatile uint32_t timestamp_ms;
121
124
127
130
133
135typedef enum : uint32_t {
136 k_pdm_demo_magic = 0x50444D31U,
138
139/* =============================================================================
140 * Banners
141 * =============================================================================
142 */
143
144static const uint8_t k_pdm_demo_banner_init[] = "pdm: init ch=2 clk=4mhz fs=16khz\r\n";
145static const uint8_t k_pdm_demo_banner_fail[] = "pdm: init FAIL\r\n";
146static const uint8_t k_pdm_demo_banner_nodat[] = "pdm: no data (FIFO empty) -- clock/mic?\r\n";
147static const uint8_t k_pdm_demo_banner_pass[] = "pdm: verdict=PASS active=Y\r\n";
148static const uint8_t k_pdm_demo_banner_inactive[] = "pdm: verdict=FAIL active=N\r\n";
149
150/* =============================================================================
151 * Halt + tiny serialisers
152 * =============================================================================
153 */
154
170static void pdm_demo_panic_halt(void)
171{
172 while (1) {
173 __asm__ volatile("wfi");
174 }
175}
176
196static uint32_t pdm_demo_i32_to_dec(int32_t value, uint8_t* out)
197{
198 uint8_t tmp[k_pdm_demo_int_str_cap] = {};
199 uint32_t n = 0U;
200 bool neg = value < 0;
201 /* Work in int64 so INT32_MIN negates without overflow. */
202 int64_t v = value;
203 if (neg) {
204 v = -v;
205 }
206 if (v == 0) {
207 tmp[n++] = (uint8_t)'0';
208 } else {
209 while (v > 0 && n < (uint32_t)k_pdm_demo_int_str_cap) {
210 tmp[n++] = (uint8_t)('0' + (uint8_t)(v % (int64_t)k_pdm_demo_decimal));
211 v /= (int64_t)k_pdm_demo_decimal;
212 }
213 }
214 if (neg && n < (uint32_t)k_pdm_demo_int_str_cap) {
215 tmp[n++] = (uint8_t)'-';
216 }
217 for (uint32_t i = 0U; i < n; ++i) {
218 out[i] = tmp[n - 1U - i];
219 }
220 if (n < (uint32_t)k_pdm_demo_int_str_cap) {
221 out[n] = 0U;
222 }
223 return n;
224}
225
244static uint32_t pdm_demo_isqrt(uint64_t value)
245{
246 uint64_t rem = 0U;
247 uint64_t root = 0U;
248 for (int32_t i = 0; i < (int32_t)k_pdm_isqrt_steps; ++i) {
249 root <<= 1;
250 rem = (rem << 2) | (value >> (uint32_t)k_pdm_isqrt_top2);
251 value <<= 2;
252 ++root;
253 if (root <= rem) {
254 rem -= root;
255 ++root;
256 } else {
257 --root;
258 }
259 }
260 return (uint32_t)(root >> 1);
261}
262
280static void pdm_demo_tx(const uint8_t* bytes, uint32_t len)
281{
282 (void)ra8_board_uart_console_write(bytes, (size_t)len);
283}
284
303static void pdm_demo_emit_kv(const uint8_t* label, uint32_t label_len, int32_t value)
304{
305 uint8_t buf[k_pdm_demo_int_str_cap] = {};
306 pdm_demo_tx(label, label_len);
307 const uint32_t n = pdm_demo_i32_to_dec(value, buf);
308 pdm_demo_tx(buf, n);
309}
310
311/* =============================================================================
312 * Bring-up
313 * =============================================================================
314 */
315
331static void pdm_demo_clocks_or_halt(void)
332{
333 ra8_board_clock_rates_t clock_rates = {};
334 if (ra8_board_clocks_init(&clock_rates) != k_ra8_ok) {
336 }
337 if (ra8_mstp_init() != k_ra8_ok) {
339 }
340 if (ra8_time_init(clock_rates.cpuclk0_hz) != k_ra8_ok) {
342 }
343}
344
370
387static void pdm_demo_pdm_or_halt(void)
388{
390 ra8_board_pdm_mic_config_t board_cfg = {};
394 }
395 const ra8_audio_source_pdm_cfg_t source_cfg = {
396 .pdm = board_cfg.pdm,
397 .sample_rate_hz = board_cfg.sample_rate_hz,
398 .samples_per_frame = (uint32_t)k_pdm_demo_window,
399 .settle_ms = (uint32_t)k_pdm_demo_settle_ms,
400 .discard_samples = (uint32_t)k_pdm_demo_discard,
401 .poll_attempts = (uint32_t)k_pdm_demo_poll_max,
402 .channel = board_cfg.channel,
403 .valid_bits = board_cfg.valid_bits,
404 };
406 k_ra8_ok) {
409 }
410}
411
412/* =============================================================================
413 * Capture + analysis
414 * =============================================================================
415 */
416
439static void pdm_demo_analyze(const int32_t* buf, uint32_t n, pdm_metrics_t* m)
440{
441 if (n == 0U) {
442 *m = (pdm_metrics_t){};
443 return;
444 }
445 int64_t sum = 0;
446 int32_t lo = buf[0];
447 int32_t hi = buf[0];
448 for (uint32_t i = 0U; i < n; ++i) {
449 const int32_t s = buf[i];
450 sum += s;
451 lo = (s < lo) ? s : lo;
452 hi = (s > hi) ? s : hi;
453 }
454 const int32_t mean = (int32_t)(sum / (int64_t)n);
455
456 uint64_t sumsq = 0U;
457 int32_t peak = 0;
458 for (uint32_t i = 0U; i < n; ++i) {
459 const int32_t d = buf[i] - mean;
460 const int32_t mag = (d < 0) ? -d : d;
461 peak = (mag > peak) ? mag : peak;
462 sumsq += (uint64_t)((int64_t)d * (int64_t)d);
463 }
464 m->min = lo;
465 m->max = hi;
466 m->mean = mean;
467 m->peak = peak;
468 m->rms = (int32_t)pdm_demo_isqrt(sumsq / (uint64_t)n);
469 m->n = n;
470}
471
494{
495 const int32_t span = m->max - m->min;
496 if (span >= (int32_t)k_pdm_demo_min_span) {
497 if (m->rms >= (int32_t)k_pdm_demo_rms_floor) {
498 return true;
499 }
500 }
501 return false;
502}
503
522static void pdm_demo_publish(const pdm_metrics_t* m, int32_t vary, bool active)
523{
524 static const uint8_t k_l_rms[] = "pdm: rms=";
525 static const uint8_t k_l_peak[] = " peak=";
526 static const uint8_t k_l_mean[] = " mean=";
527 static const uint8_t k_l_span[] = " span=";
528 static const uint8_t k_l_vary[] = " vary=";
529 static const uint8_t k_l_act[] = " active=";
530 static const uint8_t k_l_y[] = "Y\r\n";
531 static const uint8_t k_l_n[] = "N\r\n";
532
533 pdm_demo_emit_kv(k_l_rms, (uint32_t)(sizeof(k_l_rms) - 1U), m->rms);
534 pdm_demo_emit_kv(k_l_peak, (uint32_t)(sizeof(k_l_peak) - 1U), m->peak);
535 pdm_demo_emit_kv(k_l_mean, (uint32_t)(sizeof(k_l_mean) - 1U), m->mean);
536 pdm_demo_emit_kv(k_l_span, (uint32_t)(sizeof(k_l_span) - 1U), m->max - m->min);
537 pdm_demo_emit_kv(k_l_vary, (uint32_t)(sizeof(k_l_vary) - 1U), vary);
538 pdm_demo_tx(k_l_act, (uint32_t)(sizeof(k_l_act) - 1U));
539 if (active) {
540 pdm_demo_tx(k_l_y, (uint32_t)(sizeof(k_l_y) - 1U));
541 } else {
542 pdm_demo_tx(k_l_n, (uint32_t)(sizeof(k_l_n) - 1U));
543 }
544
545 g_pdm_mic_result.rms = m->rms;
546 g_pdm_mic_result.peak = m->peak;
547 g_pdm_mic_result.mean = m->mean;
548 g_pdm_mic_result.span = m->max - m->min;
549 g_pdm_mic_result.vary = vary;
550 g_pdm_mic_result.samples = m->n;
551 g_pdm_mic_result.active = active ? 1U : 0U;
552 g_pdm_mic_result.windows = g_pdm_mic_result.windows + 1U;
553 g_pdm_mic_result.magic = (uint32_t)k_pdm_demo_magic;
554}
555
577static bool pdm_demo_run_window(int32_t vary, pdm_metrics_t* out_m)
578{
579 const ra8_audio_buffer_t buffer = {
580 .data = s_pdm_demo_buf,
581 .capacity = (uint32_t)sizeof(s_pdm_demo_buf),
582 };
583 ra8_audio_frame_t frame = {};
584 if (ra8_audio_source_capture(&s_pdm_demo_source, &buffer, &frame) != k_ra8_ok) {
586 return false;
587 }
589 const bool active = pdm_demo_is_active(out_m);
590 pdm_demo_publish(out_m, vary, active);
591 g_pdm_mic_result.timestamp_ms = frame.timestamp_ms;
592 return true;
593}
594
595/* =============================================================================
596 * Main
597 * =============================================================================
598 */
599
610void main(void)
611{
615
616 pdm_metrics_t m = {};
617 /* Sweep windows for the verdict, tracking the RMS spread. */
618 int32_t rms_lo = INT32_MAX;
619 int32_t rms_hi = 0;
620 uint32_t active_windows = 0U;
621 for (uint32_t w = 0U; w < (uint32_t)k_pdm_demo_report_win; ++w) {
622 const int32_t vary = (rms_hi > rms_lo) ? (rms_hi - rms_lo) : 0;
623 if (!pdm_demo_run_window(vary, &m)) {
625 }
626 rms_lo = (m.rms < rms_lo) ? m.rms : rms_lo;
627 rms_hi = (m.rms > rms_hi) ? m.rms : rms_hi;
628 active_windows += (g_pdm_mic_result.active != 0U) ? 1U : 0U;
629 }
630 if (active_windows == 0U) {
633 }
635 while (1) {
636 __asm__ volatile("wfi");
637 }
638
640}
void main(void)
Secure fallback main entry point.
Definition main.c:37
pdm_demo_magic_t
Result magic marker ('PDM1').
Definition main.c:135
@ k_pdm_demo_magic
Pdm demo magic.
Definition main.c:136
static uint32_t pdm_demo_isqrt(uint64_t value)
Integer square root of a 64-bit value (floor).
Definition main.c:244
pdm_demo_threshold_t
Plausibility thresholds (20-bit signed full scale = +-524288).
Definition main.c:68
@ k_pdm_demo_min_span
Min peak-to-peak to be non-degenerate.
Definition main.c:69
@ k_pdm_demo_rms_floor
Min AC RMS to count as live audio.
Definition main.c:70
static ra8_audio_source_pdm_state_t s_pdm_demo_source_state
Caller-owned PDM backend state.
Definition main.c:132
static const uint8_t k_pdm_demo_banner_inactive[]
Definition main.c:148
static void pdm_demo_io_or_halt(void)
Route P812/P502 to the PDM function and open the console.
Definition main.c:360
pdm_isqrt_const_t
Integer-sqrt bit-window constants (64-bit radicand).
Definition main.c:79
@ k_pdm_isqrt_top2
Shift to the top 2 bits of a 64-bit word.
Definition main.c:81
@ k_pdm_isqrt_steps
32 two-bit steps span a 64-bit radicand.
Definition main.c:80
static const uint8_t k_pdm_demo_banner_fail[]
Definition main.c:145
static ra8_audio_source_t s_pdm_demo_source
Generic caller-owned audio source handle.
Definition main.c:129
volatile pdm_mic_result_t g_pdm_mic_result
J-Link-probable capture result (read at &g_pdm_mic_result).
Definition main.c:123
static void pdm_demo_clocks_or_halt(void)
Bring CGC + MSTP + SysTick up; halts on any failure.
Definition main.c:331
static void pdm_demo_analyze(const int32_t *buf, uint32_t n, pdm_metrics_t *m)
Compute min/max/mean/peak/RMS for a captured window.
Definition main.c:439
static void pdm_demo_tx(const uint8_t *bytes, uint32_t len)
Emit a byte run over the SCI8 console.
Definition main.c:280
static void pdm_demo_pdm_or_halt(void)
Bind the on-board MIC1 through the reusable PDM audio source.
Definition main.c:387
static const uint8_t k_pdm_demo_banner_pass[]
Definition main.c:147
pdm_demo_const_t
App-wide tunables.
Definition main.c:57
@ k_pdm_demo_settle_ms
Mic wake-up + filter settle delay.
Definition main.c:60
@ k_pdm_demo_window
PCM samples per analysis window.
Definition main.c:61
@ k_pdm_demo_report_win
Windows swept for the verdict banner.
Definition main.c:63
@ k_pdm_demo_discard
Transient samples discarded up front.
Definition main.c:62
@ k_pdm_demo_decimal
Radix for integer-to-ASCII.
Definition main.c:59
@ k_pdm_demo_poll_max
Bounded capture poll retries (dead-mic).
Definition main.c:64
@ k_pdm_demo_baud
SCI8 console baud.
Definition main.c:58
static void pdm_demo_publish(const pdm_metrics_t *m, int32_t vary, bool active)
Print a per-window detail line and latch g_pdm_mic_result.
Definition main.c:522
static bool pdm_demo_run_window(int32_t vary, pdm_metrics_t *out_m)
Capture one window, analyse it and publish it.
Definition main.c:577
static bool pdm_demo_is_active(const pdm_metrics_t *m)
Decide whether a window carries plausible live audio.
Definition main.c:493
static void pdm_demo_panic_halt(void)
Park forever after a fatal error.
Definition main.c:170
static const uint8_t k_pdm_demo_banner_nodat[]
Definition main.c:146
pdm_demo_str_cap_t
Sizing for the decimal serialiser buffer ("-2147483648" + NUL).
Definition main.c:74
@ k_pdm_demo_int_str_cap
Pdm demo int str cap.
Definition main.c:75
static const uint8_t k_pdm_demo_banner_init[]
Definition main.c:144
static uint32_t pdm_demo_i32_to_dec(int32_t value, uint8_t *out)
Convert a signed 32-bit int into a decimal ASCII string.
Definition main.c:196
static void pdm_demo_emit_kv(const uint8_t *label, uint32_t label_len, int32_t value)
Emit "<label><value>" with a decimal integer.
Definition main.c:303
static int32_t s_pdm_demo_buf[k_pdm_demo_window]
Static capture buffer (kept off the stack).
Definition main.c:126
Transport-neutral, caller-owned audio capture facade.
ra8_err_t ra8_audio_source_capture(ra8_audio_source_t *source, const ra8_audio_buffer_t *buffer, ra8_audio_frame_t *out_frame)
Capture one fixed-size PCM frame into caller-owned storage.
Definition ra8_audio.c:190
RA8 PDM-IF backend for the transport-neutral audio facade.
ra8_err_t ra8_audio_source_pdm_init(ra8_audio_source_t *source, ra8_audio_source_pdm_state_t *state, const ra8_audio_source_pdm_cfg_t *cfg)
Configure, start, settle, and bind one PDM audio source.
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
ra8_err_t ra8_board_led_init(ra8_board_led_id_t led)
Configure led as a digital output, initial level low (off).
@ k_ra8_board_led1
LED1, BLUE, P600 (jumper E27).
ra8_err_t ra8_board_pdm_mic_get_config(ra8_board_pdm_mic_t microphone, ra8_board_pdm_mic_config_t *out_config)
Return the validated SPH0690 filter policy for one board microphone.
@ k_ra8_board_pdm_mic1
Rising-edge MIC1 (SELECT tied low).
ra8_err_t ra8_board_pdm_mic_route(void)
Route P812/P502 to PDMCLK2/PDMDAT2.
ra8_err_t ra8_board_clocks_init(ra8_board_clock_rates_t *out_rates)
Initialize the standard EK-RA8D2 clock tree and return its rates.
ra8_err_t ra8_board_uart_console_write(const uint8_t *data, size_t len)
Polled blocking write to the J-Link OB VCOM console.
ra8_err_t ra8_board_uart_console_init(uint32_t baud)
Configure SCI8 + PD02/PD03 as the debug-console UART.
Boot entry points shared between a vector table and its startup code.
Error Code Definitions for ra8-firmware.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
Ref-counted Module Stop Control wrapper for the RA8D2.
ra8_err_t ra8_mstp_init(void)
Re-establish the ra8_mstp ref-count table from current hardware state.
Definition ra8_mstp.c:291
SysTick-based tick counter, delay and timestamp helpers.
ra8_err_t ra8_time_init(uint32_t cpu_hz)
Initialise SysTick for a 1 kHz tick interrupt.
Definition ra8_time.c:59
Statistics for one captured PCM window.
Definition main.c:93
int32_t min
Minimum sample.
Definition main.c:94
int32_t peak
Peak |sample - mean| (AC peak).
Definition main.c:97
int32_t mean
DC mean (near 0 after the HPF).
Definition main.c:96
uint32_t n
Samples analysed.
Definition main.c:99
int32_t max
Maximum sample.
Definition main.c:95
int32_t rms
AC RMS about the mean.
Definition main.c:98
Debugger-probable capture result.
Definition main.c:108
volatile uint32_t magic
0x50444D31 ('PDM1') once a window is done.
Definition main.c:109
volatile uint32_t timestamp_ms
Latest frame capture-start timestamp.
Definition main.c:119
volatile int32_t peak
Latest window AC peak.
Definition main.c:111
volatile uint32_t active
1 = plausible live audio, 0 = degenerate.
Definition main.c:116
volatile int32_t mean
Latest window DC mean.
Definition main.c:112
volatile uint32_t samples
Samples in the latest window.
Definition main.c:115
volatile uint32_t windows
Windows captured so far.
Definition main.c:117
volatile int32_t vary
RMS spread across the report sweep.
Definition main.c:114
volatile int32_t rms
Latest window AC RMS.
Definition main.c:110
volatile int32_t span
Latest window max-min.
Definition main.c:113
Caller-owned writable byte buffer.
Definition ra8_audio.h:44
Immutable view of one interleaved PCM frame.
Definition ra8_audio.h:56
uint32_t sample_count
Sample frames per channel.
Definition ra8_audio.h:59
uint32_t timestamp_ms
Capture-start monotonic milliseconds.
Definition ra8_audio.h:61
Complete PDM source initialization and capture policy.
Caller-owned mutable state for one PDM source backend.
Caller-owned handle binding an audio source backend and its state.
Definition ra8_audio.h:78
Clock rates published by the standard EK-RA8D2 bring-up.
uint32_t cpuclk0_hz
Main Cortex-M85 clock rate in hertz.
Board-owned PDM mechanism configuration for one microphone.
uint8_t channel
PDM-IF channel selector.
uint32_t sample_rate_hz
Decimated PCM sample rate.
ra8_pdm_channel_cfg_t pdm
SPH0690 filter coefficients.
uint8_t valid_bits
Significant PCM bits.