ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_audio_source_pdm.c
Go to the documentation of this file.
1
15
17
18#include <stdint.h>
19#include <string.h>
20
21#include "ra8_audio_internal.h"
22#include "ra8_time.h"
23
24typedef enum : uintptr_t {
27
46internal_pdm_fill(uint8_t channel, int32_t* samples, uint32_t count, uint32_t attempts)
47{
48 uint32_t filled = 0U;
49 for (uint32_t attempt = 0U; attempt < attempts; attempt += 1U) {
50 if (filled == count) {
51 return k_ra8_ok;
52 }
53 uint32_t got = 0U;
54 ra8_err_t err = ra8_pdm_read(channel, &samples[filled], count - filled, &got);
55 if (err != k_ra8_ok) {
56 return err;
57 }
58 filled += got;
59 }
61}
62
79{
81 if (state == nullptr) {
83 }
84 if (!state->initialized) {
86 }
87 *out_info = state->info;
88 return k_ra8_ok;
89}
90
105RA8_INTERNAL static void internal_pdm_stream_data(void* ctx, const int32_t* samples, uint32_t count)
106{
108 if (state == nullptr) {
109 return;
110 }
111 if (!state->streaming) {
112 return;
113 }
114 uint32_t consumed = 0U;
115 while (consumed < count) {
116 if (state->stream_filled == 0U) {
118 }
119 const uint32_t remaining = state->info.samples_per_frame - state->stream_filled;
120 const uint32_t available = count - consumed;
121 const uint32_t copy = (available < remaining) ? available : remaining;
122 int32_t* output = (int32_t*)state->stream_data;
123 (void)memcpy(&output[state->stream_filled], &samples[consumed], copy * sizeof(int32_t));
124 state->stream_filled += copy;
125 consumed += copy;
126 if (state->stream_filled == state->info.samples_per_frame) {
127 const ra8_audio_frame_t frame = {
128 .data = state->stream_data,
129 .bytes = state->info.frame_bytes,
130 .sample_count = state->info.samples_per_frame,
131 .sample_rate_hz = state->info.sample_rate_hz,
132 .timestamp_ms = state->stream_timestamp_ms,
133 .channels = state->info.channels,
134 .valid_bits = state->info.valid_bits,
135 .format = state->info.format,
136 };
137 state->stream_filled = 0U;
138 state->stream_callback(state->stream_ctx, &frame);
139 }
140 }
141}
142
162internal_pdm_capture(void* ctx, const ra8_audio_buffer_t* buffer, ra8_audio_frame_t* out_frame)
163{
165 if (state == nullptr) {
167 }
168 if (!state->initialized) {
170 }
171 if (buffer->capacity < state->info.frame_bytes) {
173 }
174 if (((uintptr_t)buffer->data & (uintptr_t)k_pdm_source_alignment_mask) != 0U) {
176 }
177 const uint32_t timestamp_ms = ra8_time_ms();
178 const ra8_err_t err = internal_pdm_fill(state->channel,
179 (int32_t*)buffer->data,
180 state->info.samples_per_frame,
181 state->poll_attempts);
182 if (err != k_ra8_ok) {
183 return err;
184 }
185 *out_frame = (ra8_audio_frame_t){
186 .data = buffer->data,
187 .bytes = state->info.frame_bytes,
188 .sample_count = state->info.samples_per_frame,
189 .sample_rate_hz = state->info.sample_rate_hz,
190 .timestamp_ms = timestamp_ms,
191 .channels = state->info.channels,
192 .valid_bits = state->info.valid_bits,
193 .format = state->info.format,
194 };
195 return k_ra8_ok;
196}
197
213{
215 if (state == nullptr) {
217 }
218 if (!state->initialized) {
220 }
221 const ra8_err_t stop_err = ra8_pdm_stop(state->channel);
222 if (stop_err != k_ra8_ok) {
223 return stop_err;
224 }
225 const ra8_err_t deinit_err = ra8_pdm_deinit();
226 if (deinit_err == k_ra8_ok) {
227 state->initialized = false;
228 }
229 return deinit_err;
230}
231
252 const ra8_audio_buffer_t* buffer,
254 void* callback_ctx)
255{
257 if (state == nullptr) {
259 }
260 if (!state->initialized) {
262 }
263 if (state->streaming) {
264 return k_ra8_err_exists;
265 }
266 if (((uintptr_t)buffer->data & (uintptr_t)k_pdm_source_alignment_mask) != 0U) {
268 }
269 state->stream_data = buffer->data;
270 state->stream_callback = callback;
271 state->stream_ctx = callback_ctx;
272 state->stream_filled = 0U;
273 state->stream_timestamp_ms = 0U;
274 state->streaming = true;
275 const ra8_err_t err =
277 if (err != k_ra8_ok) {
278 state->streaming = false;
279 state->stream_data = nullptr;
280 state->stream_callback = nullptr;
281 state->stream_ctx = nullptr;
282 }
283 return err;
284}
285
287 .get_info = internal_pdm_get_info,
288 .capture = internal_pdm_capture,
289 .stream_start = internal_pdm_stream_start,
290 .stop = internal_pdm_stop,
291};
292
311 uint32_t* out_frame_bytes)
312{
313 if (cfg->channel >= (uint8_t)k_ra8_pdm_ch_count) {
315 }
316 if (cfg->sample_rate_hz == 0U) {
318 }
319 if (cfg->samples_per_frame == 0U) {
321 }
322 if (cfg->poll_attempts == 0U) {
324 }
325 if (cfg->valid_bits == 0U) {
327 }
328 if (cfg->valid_bits > 32U) {
330 }
331 const uint64_t frame_bytes = (uint64_t)cfg->samples_per_frame * sizeof(int32_t);
332 if (frame_bytes > UINT32_MAX) {
334 }
335 *out_frame_bytes = (uint32_t)frame_bytes;
336 return k_ra8_ok;
337}
338
355{
356 ra8_err_t err = ra8_pdm_init();
357 if (err != k_ra8_ok) {
358 return err;
359 }
360 err = ra8_pdm_configure(cfg->channel, &cfg->pdm);
361 if (err == k_ra8_ok) {
362 err = ra8_pdm_start(cfg->channel);
363 }
364 if (err != k_ra8_ok) {
365 (void)ra8_pdm_deinit();
366 return err;
367 }
369 err = ra8_pdm_read_enable(cfg->channel);
370 int32_t discard = 0;
371 for (uint32_t i = 0U; i < cfg->discard_samples; i += 1U) {
372 if (err != k_ra8_ok) {
373 break;
374 }
375 err = internal_pdm_fill(cfg->channel, &discard, 1U, cfg->poll_attempts);
376 }
377 if (err != k_ra8_ok) {
378 (void)ra8_pdm_stop(cfg->channel);
379 (void)ra8_pdm_deinit();
380 }
381 return err;
382}
383
387{
388 if (source == nullptr) {
389 return k_ra8_err_null_ptr;
390 }
391 if (state == nullptr) {
392 return k_ra8_err_null_ptr;
393 }
394 if (cfg == nullptr) {
395 return k_ra8_err_null_ptr;
396 }
397 *source = (ra8_audio_source_t){};
398 *state = (ra8_audio_source_pdm_state_t){};
399 uint32_t frame_bytes = 0U;
400 ra8_err_t err = internal_pdm_validate_cfg(cfg, &frame_bytes);
401 if (err != k_ra8_ok) {
402 return err;
403 }
405 if (err != k_ra8_ok) {
406 return err;
407 }
409 .info =
410 {
411 .frame_bytes = frame_bytes,
412 .samples_per_frame = cfg->samples_per_frame,
413 .sample_rate_hz = cfg->sample_rate_hz,
414 .channels = 1U,
415 .valid_bits = cfg->valid_bits,
417 },
418 .poll_attempts = cfg->poll_attempts,
419 .channel = cfg->channel,
420 .irq_priority = cfg->irq_priority,
421 .initialized = true,
422 };
423 *source = (ra8_audio_source_t){
424 .iface = &s_pdm_source_iface,
425 .ctx = state,
426 };
427 return k_ra8_ok;
428}
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
void(* ra8_audio_frame_callback_t)(void *ctx, const ra8_audio_frame_t *frame)
Complete-frame callback for asynchronous audio sources.
Definition ra8_audio.h:93
@ k_ra8_audio_format_pcm_s32le
Signed 32-bit little-endian PCM.
Definition ra8_audio.h:40
struct ra8_audio_source_iface ra8_audio_source_iface_t
Opaque source vtable implemented by concrete audio backends.
Definition ra8_audio.h:30
Private audio-source vtable shared by concrete backends.
static ra8_err_t internal_pdm_capture(void *ctx, const ra8_audio_buffer_t *buffer, ra8_audio_frame_t *out_frame)
Capture one fixed-size PDM frame by polling.
ra8_audio_pdm_alignment_t
@ k_pdm_source_alignment_mask
PCM-S32LE buffer alignment mask.
static ra8_err_t internal_pdm_prepare_hardware(const ra8_audio_source_pdm_cfg_t *cfg)
Initialize, settle, and prime one PDM hardware channel.
static const ra8_audio_source_iface_t s_pdm_source_iface
static ra8_err_t internal_pdm_stream_start(void *ctx, const ra8_audio_buffer_t *buffer, ra8_audio_frame_callback_t callback, void *callback_ctx)
Bind persistent scratch and enable PDM FIFO interrupts.
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.
static void internal_pdm_stream_data(void *ctx, const int32_t *samples, uint32_t count)
Assemble FIFO chunks into the caller's fixed-size audio frame.
static ra8_err_t internal_pdm_validate_cfg(const ra8_audio_source_pdm_cfg_t *cfg, uint32_t *out_frame_bytes)
Validate PDM source geometry and compute its frame size.
static ra8_err_t internal_pdm_fill(uint8_t channel, int32_t *samples, uint32_t count, uint32_t attempts)
Fill a sample span from the PDM FIFO.
static ra8_err_t internal_pdm_get_info(void *ctx, ra8_audio_source_info_t *out_info)
Report the initialized PDM source geometry.
static ra8_err_t internal_pdm_stop(void *ctx)
Stop and deinitialize the PDM source.
RA8 PDM-IF backend for the transport-neutral audio facade.
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_exists
Item already exists – cannot create again.
Definition ra8_err.h:216
@ k_ra8_err_hw_timeout
Hardware timed out waiting for a flag or handshake.
Definition ra8_err.h:304
@ k_ra8_err_not_initialized
Module not initialized – _init() not yet called successfully.
Definition ra8_err.h:235
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
ra8_err_t ra8_pdm_stop(uint8_t ch)
Stop a channel and wait for its filter to halt.
Definition ra8_pdm.c:332
ra8_err_t ra8_pdm_init(void)
Release the PDM-IF module stop and reset its common bank.
Definition ra8_pdm.c:211
ra8_err_t ra8_pdm_read_enable(uint8_t ch)
Clear status, enable data read and prime the receive FIFO.
Definition ra8_pdm.c:254
ra8_err_t ra8_pdm_configure(uint8_t ch, const ra8_pdm_channel_cfg_t *cfg)
Program a channel's mode, decimation and filter coefficients.
Definition ra8_pdm.c:233
ra8_err_t ra8_pdm_stream_enable(uint8_t ch, ra8_pdm_data_callback_t callback, void *ctx, uint8_t priority)
Enable interrupt-driven FIFO delivery for one running channel.
Definition ra8_pdm.c:294
@ k_ra8_pdm_ch_count
Number of channels (bound).
Definition ra8_pdm.h:60
ra8_err_t ra8_pdm_start(uint8_t ch)
Activate a configured channel's filter (start trigger).
Definition ra8_pdm.c:246
ra8_err_t ra8_pdm_deinit(void)
Put the PDM-IF block back into module stop.
Definition ra8_pdm.c:225
ra8_err_t ra8_pdm_read(uint8_t ch, int32_t *out, uint32_t max, uint32_t *out_count)
Drain up to max PCM samples from a channel's FIFO.
Definition ra8_pdm.c:271
SysTick-based tick counter, delay and timestamp helpers.
void ra8_delay_ms(uint32_t ms)
Busy-wait for at least ms milliseconds.
Definition ra8_time.c:129
uint32_t ra8_time_ms(void)
Get the current 1 kHz tick count.
Definition ra8_time.c:108
Caller-owned writable byte buffer.
Definition ra8_audio.h:44
uint32_t capacity
Writable capacity in bytes.
Definition ra8_audio.h:46
void * data
First writable byte.
Definition ra8_audio.h:45
Immutable view of one interleaved PCM frame.
Definition ra8_audio.h:56
Fixed output contract and storage requirement for one source.
Definition ra8_audio.h:68
uint8_t valid_bits
Significant bits per sample.
Definition ra8_audio.h:73
uint32_t samples_per_frame
Sample frames returned per call.
Definition ra8_audio.h:70
ra8_audio_format_t format
PCM container layout.
Definition ra8_audio.h:74
uint32_t frame_bytes
Required capture-buffer capacity.
Definition ra8_audio.h:69
uint32_t sample_rate_hz
Sample frames per second.
Definition ra8_audio.h:71
uint8_t channels
Interleaved channel count.
Definition ra8_audio.h:72
Complete PDM source initialization and capture policy.
ra8_pdm_channel_cfg_t pdm
HAL filter configuration.
uint8_t channel
ra8_pdm_channel_t selector.
uint32_t sample_rate_hz
Decimated PCM sample rate.
uint32_t discard_samples
Startup samples to discard.
uint8_t irq_priority
Async-stream NVIC priority.
uint8_t valid_bits
Significant bits in PCM-S32LE.
uint32_t poll_attempts
Empty-FIFO retry bound/frame.
uint32_t settle_ms
Mic/filter startup delay.
uint32_t samples_per_frame
Samples returned per capture.
Caller-owned mutable state for one PDM source backend.
uint32_t stream_timestamp_ms
Current frame timestamp.
ra8_audio_source_info_t info
Fixed output contract.
uint32_t poll_attempts
Empty-FIFO retry bound.
void * stream_ctx
Callback context.
void * stream_data
Persistent stream scratch.
bool initialized
Hardware source is running.
ra8_audio_frame_callback_t stream_callback
Complete-frame callback.
uint8_t irq_priority
Async-stream NVIC priority.
uint8_t channel
Bound PDM channel.
bool streaming
Interrupt delivery enabled.
uint32_t stream_filled
Samples currently assembled.
Caller-owned handle binding an audio source backend and its state.
Definition ra8_audio.h:78