ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_pdm.c File Reference

Pulse Density Modulation Interface (PDM-IF) capture driver. More...

#include "ra8_pdm.h"
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_isr.h"
#include "ra8_log.h"
#include "ra8_mstp.h"
#include "ra8_mstp_regs.h"
#include "ra8_pdm_regs.h"
Include dependency graph for ra8_pdm.c:

Go to the source code of this file.

Data Structures

struct  pdm_stream_state_t
 Per-channel interrupt callback binding. More...

Enumerations

enum  pdm_impl_const_t : uint32_t {
  k_pdm_prime_discards = 30U ,
  k_pdm_stop_poll_max = 1000U ,
  k_pdm_field_3bit = 0x7U
}
 Implementation-local bounds (HUM Ch 49 "Normal Processing Flow"). More...

Functions

static void internal_pdm_write_mode (volatile r_pdm_ch_regs_t *reg, const ra8_pdm_channel_cfg_t *cfg)
 Write a channel's PDMDSR + PDSFCR mode/decimation words.
static void internal_pdm_write_coeffs (volatile r_pdm_ch_regs_t *reg, const ra8_pdm_channel_cfg_t *cfg)
 Write a channel's high-pass, compensation and low-pass coefficients.
static int32_t internal_pdm_sign_extend20 (uint32_t raw)
 Sign-extend one 20-bit PDDRR sample to a full int32_t.
static void internal_pdm_data_isr (void *ctx)
 Drain one PDM FIFO threshold and dispatch its signed samples.
ra8_err_t ra8_pdm_init (void)
 Release the PDM-IF module stop and reset its common bank.
ra8_err_t ra8_pdm_deinit (void)
 Put the PDM-IF block back into module stop.
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.
ra8_err_t ra8_pdm_start (uint8_t ch)
 Activate a configured channel's filter (start trigger).
ra8_err_t ra8_pdm_read_enable (uint8_t ch)
 Clear status, enable data read and prime the receive FIFO.
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.
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.
ra8_err_t ra8_pdm_stream_disable (uint8_t ch)
 Disable interrupt-driven delivery for one channel.
ra8_err_t ra8_pdm_stop (uint8_t ch)
 Stop a channel and wait for its filter to halt.

Variables

static const char * s_tag = "PDM"
static pdm_stream_state_t s_streams [k_ra8_pdm_ch_count]
static const ra8_elc_event_t s_pdm_data_events [k_ra8_pdm_ch_count]

Detailed Description

Pulse Density Modulation Interface (PDM-IF) capture driver.

Tag
[Ring 3 / HAL] {World: NS}

Polling-mode capture driver for the RA8D2 PDM-IF block. Implements the HUM Ch 49.4.1 "Start Flow": configure a channel's mode + decimation + FIR coefficients, activate the filter, prime the FIFO and drain 20-bit signed PCM from the data-read register. The hardware performs the PDM->PCM decimation; this driver only sequences and reads it. Every register access carries a HUM Ch 49 citation.

Definition in file ra8_pdm.c.

Enumeration Type Documentation

◆ pdm_impl_const_t

enum pdm_impl_const_t : uint32_t

Implementation-local bounds (HUM Ch 49 "Normal Processing Flow").

Enumerator
k_pdm_prime_discards 

FIFO depth (32) minus 2 priming reads.

k_pdm_stop_poll_max 

Bounded stop-poll retry budget.

k_pdm_field_3bit 

3-bit field mask (SFMD).

Definition at line 53 of file ra8_pdm.c.

Function Documentation

◆ internal_pdm_data_isr()

void internal_pdm_data_isr ( void * ctx)
static

Drain one PDM FIFO threshold and dispatch its signed samples.

Bounds the hardware-reported fill level to the FIFO depth, converts each 20-bit word, and invokes the registered channel callback once.

Parameters
[in]ctxEncoded channel index.
Precondition
Registered only by ra8_pdm_stream_enable.
The channel callback remains valid until stream disable completes.
Postcondition
Available FIFO samples are consumed and delivered once.
Invalid channels and unregistered callbacks return without MMIO access.
Note
Runs in interrupt context.
Since
0.1.0

Definition at line 185 of file ra8_pdm.c.

References pdm_stream_state_t::callback, pdm_stream_state_t::ctx, internal_pdm_sign_extend20(), k_ra8_pdm_ch_count, k_ra8_pdm_fifo_depth, k_ra8_pdm_pddsr_num_mask, r_pdm_ch_regs_t::PDDRR, r_pdm_ch_regs_t::PDDSR, RA8_INTERNAL, ra8_pdm_ch(), and s_streams.

Referenced by ra8_pdm_stream_enable().

◆ internal_pdm_sign_extend20()

int32_t internal_pdm_sign_extend20 ( uint32_t raw)
static

Sign-extend one 20-bit PDDRR sample to a full int32_t.

Masks raw to its low 20 significant bits, then, if bit 19 (the two's-complement sign bit) is set, fills the upper 12 bits with ones so the value reads as a correctly-signed int32_t; otherwise returns the masked value unchanged. Pure bit manipulation, no hardware access.

Parameters
[in]rawRaw PDDRR read (only the low 20 bits are significant).
Returns
Signed 32-bit PCM sample.
Return values
<0The 20-bit sign bit (bit 19) was set; upper bits filled with ones.
>=0The 20-bit sign bit was clear; the masked low-20-bit value.
Precondition
raw came from a PDDRR read.
The channel is producing 20-bit data (DBIS 20-bit mode).
Postcondition
The result equals raw interpreted as a 20-bit two's-complement.
No hardware state is touched.
Note
Pure helper, thread-safe.
Since
0.1.0

Definition at line 164 of file ra8_pdm.c.

References k_ra8_pdm_pddrr_dat_mask, k_ra8_pdm_pddrr_sign_bit, k_ra8_pdm_pddrr_sign_ext, and RA8_INTERNAL.

Referenced by internal_pdm_data_isr(), and ra8_pdm_read().

◆ internal_pdm_write_coeffs()

void internal_pdm_write_coeffs ( volatile r_pdm_ch_regs_t * reg,
const ra8_pdm_channel_cfg_t * cfg )
static

Write a channel's high-pass, compensation and low-pass coefficients.

Loads the three FIR banks (HPF s0/k1/h[2], compensation h[11], low-pass h0/h1[20]) that the sinc chain feeds. The values are the microphone/rate filter set carried by cfg.

Parameters
[in,out]regChannel register bank (non-NULL).
[in]cfgChannel configuration (non-NULL).
Returns
Nothing.
Precondition
reg points at a valid PDM channel bank.
cfg carries a complete coefficient set.
Postcondition
All HPF/compensation/low-pass coefficient registers hold cfg.
No mode or trigger register is modified.
Note
Not thread-safe.
Since
0.1.0

Definition at line 120 of file ra8_pdm.c.

References ra8_pdm_channel_cfg_t::comp_h, ra8_pdm_channel_cfg_t::hpf_h, ra8_pdm_channel_cfg_t::hpf_k1, ra8_pdm_channel_cfg_t::hpf_s0, k_ra8_pdm_comp_h_count, k_ra8_pdm_hpf_h_count, k_ra8_pdm_lpf_h1_count, ra8_pdm_channel_cfg_t::lpf_h0, ra8_pdm_channel_cfg_t::lpf_h1, r_pdm_ch_regs_t::PDCFCHR, r_pdm_ch_regs_t::PDHFCHR, r_pdm_ch_regs_t::PDHFCK1R, r_pdm_ch_regs_t::PDHFCS0R, r_pdm_ch_regs_t::PDLFCH010R, r_pdm_ch_regs_t::PDLFCH1R, and RA8_INTERNAL.

Referenced by ra8_pdm_configure().

◆ internal_pdm_write_mode()

void internal_pdm_write_mode ( volatile r_pdm_ch_regs_t * reg,
const ra8_pdm_channel_cfg_t * cfg )
static

Write a channel's PDMDSR + PDSFCR mode/decimation words.

Packs the mode-setting fields (sinc order, filter input shifts, data shift, input edge) into PDMDSR and the clock divider + sinc decimation

  • clip range into PDSFCR.
Parameters
[in,out]regChannel register bank (non-NULL).
[in]cfgChannel configuration (non-NULL).
Returns
Nothing.
Precondition
reg points at a valid PDM channel bank.
cfg->sinc_order is in 1..4.
Postcondition
PDMDSR and PDSFCR hold the packed configuration.
No other channel register is modified.
Note
Not thread-safe.
Since
0.1.0

Definition at line 80 of file ra8_pdm.c.

References ra8_pdm_channel_cfg_t::cf_shift, ra8_pdm_channel_cfg_t::clock_div, ra8_pdm_channel_cfg_t::data_shift, ra8_pdm_channel_cfg_t::edge, ra8_pdm_channel_cfg_t::hpf_shift, k_pdm_field_3bit, k_ra8_pdm_pdmdsr_cfis_pos, k_ra8_pdm_pdmdsr_dbis_pos, k_ra8_pdm_pdmdsr_hfis_pos, k_ra8_pdm_pdmdsr_inpsel, k_ra8_pdm_pdmdsr_lfis_pos, k_ra8_pdm_pdmdsr_sfmd_pos, k_ra8_pdm_pdsfcr_ckdiv_pos, k_ra8_pdm_pdsfcr_sincdec_pos, k_ra8_pdm_pdsfcr_sincrng_pos, ra8_pdm_channel_cfg_t::lpf_shift, r_pdm_ch_regs_t::PDMDSR, r_pdm_ch_regs_t::PDSFCR, RA8_INTERNAL, ra8_pdm_channel_cfg_t::sinc_dec, ra8_pdm_channel_cfg_t::sinc_order, and ra8_pdm_channel_cfg_t::sinc_range.

Referenced by ra8_pdm_configure().

◆ ra8_pdm_configure()

ra8_err_t ra8_pdm_configure ( uint8_t ch,
const ra8_pdm_channel_cfg_t * cfg )
nodiscard

Program a channel's mode, decimation and filter coefficients.

Implements the configuration portion of HUM Ch 49.4.1 "Start Flow": writes PDMDSR (mode/shifts/edge), PDSFCR (clock divider, decimation, clip range), the high-pass/compensation/low-pass coefficient banks and PDDBCR (reception threshold). Does not start the channel.

Parameters
[in]chChannel index (0..2).
[in]cfgChannel configuration (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okChannel configured.
k_ra8_err_invalid_argch out of range.
k_ra8_err_null_ptrcfg was NULL.
Precondition
ra8_pdm_init succeeded.
cfg describes a HUM Table 49.7 combination.
Postcondition
The channel's filter registers hold cfg.
The channel remains stopped (no data produced yet).
Note
Not thread-safe.
Since
0.1.0

Definition at line 233 of file ra8_pdm.c.

References internal_pdm_write_coeffs(), internal_pdm_write_mode(), k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_pdm_ch_count, r_pdm_ch_regs_t::PDDBCR, RA8_CHECK_NULL_PTR, RA8_CHECK_RANGE_TAG, ra8_pdm_ch(), ra8_pdm_channel_cfg_t::rx_threshold, and s_tag.

Referenced by internal_pdm_prepare_hardware().

◆ ra8_pdm_deinit()

ra8_err_t ra8_pdm_deinit ( void )
nodiscard

Put the PDM-IF block back into module stop.

Returns
ra8_err_t Error code.
Return values
k_ra8_okModule stopped.
k_ra8_err_hw_timeoutModule-stop entry did not settle.
Precondition
ra8_pdm_init previously succeeded.
No channel is mid-capture.
Postcondition
The PDM-IF block is unclocked.
Register contents are undefined until re-init.
Note
Not thread-safe.
Since
0.1.0

Definition at line 225 of file ra8_pdm.c.

References k_ra8_mstp_pdmif, r_pdm_regs_t::PDCDRCR, ra8_mstp_disable(), and ra8_pdm().

Referenced by internal_pdm_prepare_hardware(), and internal_pdm_stop().

◆ ra8_pdm_init()

ra8_err_t ra8_pdm_init ( void )
nodiscard

Release the PDM-IF module stop and reset its common bank.

Clears the PDM-IF bit in MSTPCRC so the block is clocked, then zeroes the common start/stop/status-clear triggers to a known state. Must run before any channel configuration.

Returns
ra8_err_t Error code.
Return values
k_ra8_okModule clocked and common bank reset.
k_ra8_err_hw_timeoutModule-stop release did not settle.
Precondition
PDMIFCLK (MOCO, 8 MHz) is running.
Single-threaded init context or IRQs masked.
Postcondition
The PDM-IF block is clocked out of module stop.
Common start/stop triggers read back clear.
Note
Not thread-safe.
Since
0.1.0

Definition at line 211 of file ra8_pdm.c.

References k_ra8_mstp_pdmif, k_ra8_ok, r_pdm_regs_t::PDCDRCR, r_pdm_regs_t::PDCICR, ra8_log_info, ra8_mstp_enable(), ra8_pdm(), RA8_RETURN_ON_ERROR, and s_tag.

Referenced by internal_pdm_prepare_hardware(), and ra8_nsc_pdm_init().

◆ ra8_pdm_read()

ra8_err_t ra8_pdm_read ( uint8_t ch,
int32_t * out,
uint32_t max,
uint32_t * out_count )
nodiscard

Drain up to max PCM samples from a channel's FIFO.

Reads PDDSR for the current FIFO fill count, then pops that many (capped at max) 20-bit samples from PDDRR, sign-extending each to a full int32_t. Non-blocking: returns 0 in *out_count if the FIFO is empty.

Parameters
[in]chChannel index (0..2).
[out]outDestination sample buffer (non-NULL).
[in]maxCapacity of out in samples (>0).
[out]out_countNumber of samples written (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okZero or more samples returned.
k_ra8_err_invalid_argch out of range or max was 0.
k_ra8_err_null_ptrout or out_count was NULL.
Precondition
ra8_pdm_read_enable succeeded for ch.
out has room for max int32_t samples.
Postcondition
*out_count is in [0, max].
Each written sample is sign-extended from 20 bits.
Note
Not thread-safe.
Since
0.1.0

Definition at line 271 of file ra8_pdm.c.

References internal_pdm_sign_extend20(), k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_pdm_ch_count, k_ra8_pdm_pddsr_num_mask, r_pdm_ch_regs_t::PDDRR, r_pdm_ch_regs_t::PDDSR, RA8_CHECK_NULL_PTR, RA8_CHECK_RANGE_TAG, ra8_log_error, ra8_pdm_ch(), and s_tag.

Referenced by internal_pdm_fill().

◆ ra8_pdm_read_enable()

ra8_err_t ra8_pdm_read_enable ( uint8_t ch)
nodiscard

Clear status, enable data read and prime the receive FIFO.

Clears the channel status flags, sets PDDRCR.DATRE and performs the mandatory FIFO_DEPTH - 2 priming reads of PDDRR (discarded) that HUM Ch 49 "Normal Processing Flow" requires before valid samples flow. Call after the microphone wake-up delay.

Parameters
[in]chChannel index (0..2).
Returns
ra8_err_t Error code.
Return values
k_ra8_okData read enabled and FIFO primed.
k_ra8_err_invalid_argch out of range.
Precondition
ra8_pdm_start succeeded and the settling delay elapsed.
The channel filter reports running.
Postcondition
Subsequent ra8_pdm_read calls return live PCM samples.
The channel status flags are cleared.
Note
Not thread-safe.
Since
0.1.0

Definition at line 254 of file ra8_pdm.c.

References k_pdm_prime_discards, k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_pdm_ch_count, k_ra8_pdm_pddrcr_datre, k_ra8_pdm_pdscr_clr_all, r_pdm_ch_regs_t::PDDRCR, r_pdm_ch_regs_t::PDDRR, r_pdm_ch_regs_t::PDSCR, RA8_CHECK_RANGE_TAG, ra8_pdm_ch(), and s_tag.

Referenced by internal_pdm_prepare_hardware().

◆ ra8_pdm_start()

ra8_err_t ra8_pdm_start ( uint8_t ch)
nodiscard

Activate a configured channel's filter (start trigger).

Sets the channel's common start-trigger bit (PDCSTRTR.STRTRGn), which begins clocking PDMCLKn and running the filter chain. The caller must then wait the microphone wake-up plus filter settling time before enabling data read.

Parameters
[in]chChannel index (0..2).
Returns
ra8_err_t Error code.
Return values
k_ra8_okStart trigger issued.
k_ra8_err_invalid_argch out of range.
Precondition
ra8_pdm_configure succeeded for ch.
PDMCLKn / PDMDATn pins are routed to the PDM function.
Postcondition
The channel filter is running.
PDMCLKn is toggling at the configured rate.
Note
Not thread-safe.
Since
0.1.0

Definition at line 246 of file ra8_pdm.c.

References k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_pdm_ch_count, k_ra8_pdm_pdstrtr_strt, r_pdm_regs_t::PDCSTRTR, RA8_CHECK_RANGE_TAG, ra8_pdm(), and s_tag.

Referenced by internal_pdm_prepare_hardware().

◆ ra8_pdm_stop()

ra8_err_t ra8_pdm_stop ( uint8_t ch)
nodiscard

Stop a channel and wait for its filter to halt.

Disables data read (PDDRCR), issues the channel stop trigger (PDCSTPTR.STPTRGn) per HUM Ch 49.4.2 "Stop Flow" and polls PDCSR.STATEn until the channel reports stopped or a bounded retry budget expires.

Parameters
[in]chChannel index (0..2).
Returns
ra8_err_t Error code.
Return values
k_ra8_okChannel stopped.
k_ra8_err_invalid_argch out of range.
k_ra8_err_hw_timeoutChannel did not report stopped.
Precondition
ra8_pdm_start previously succeeded for ch.
Single-threaded context.
Postcondition
The channel filter is halted.
No further samples are produced until re-start.
Note
Not thread-safe.
Since
0.1.0

Definition at line 332 of file ra8_pdm.c.

References k_pdm_stop_poll_max, k_ra8_err_hw_timeout, k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_pdm_ch_count, k_ra8_pdm_pdsr_state, k_ra8_pdm_pdstptr_stp, r_pdm_regs_t::PDCSTPTR, r_pdm_ch_regs_t::PDDRCR, RA8_CHECK_RANGE_TAG, ra8_log_error, ra8_pdm(), ra8_pdm_ch(), ra8_pdm_stream_disable(), RA8_RETURN_ON_ERROR, s_streams, and s_tag.

Referenced by internal_pdm_prepare_hardware(), and internal_pdm_stop().

◆ ra8_pdm_stream_disable()

ra8_err_t ra8_pdm_stream_disable ( uint8_t ch)
nodiscard

Disable interrupt-driven delivery for one channel.

Parameters
[in]chChannel index (0..2).
Returns
Error code.
Return values
k_ra8_okDelivery disabled.
k_ra8_err_invalid_argChannel is invalid.
k_ra8_err_not_initializedChannel was not streaming.
otherPropagated ISR unregister error.
Precondition
No callback for this channel is currently executing.
Postcondition
The PDM data event is unregistered and callback state cleared.
Note
Not thread-safe.
Since
0.1.0

Definition at line 316 of file ra8_pdm.c.

References k_ra8_err_invalid_arg, k_ra8_err_not_initialized, k_ra8_ok, k_ra8_pdm_ch_count, k_ra8_pdm_pdicr_idre, r_pdm_ch_regs_t::PDICR, RA8_CHECK_RANGE_TAG, ra8_isr_unregister(), ra8_pdm_ch(), s_pdm_data_events, s_streams, and s_tag.

Referenced by ra8_pdm_stop().

◆ ra8_pdm_stream_enable()

ra8_err_t ra8_pdm_stream_enable ( uint8_t ch,
ra8_pdm_data_callback_t callback,
void * ctx,
uint8_t priority )
nodiscard

Enable interrupt-driven FIFO delivery for one running channel.

Parameters
[in]chChannel index (0..2).
[in]callbackBounded data callback.
[in]ctxOpaque callback context; may be nullptr.
[in]priorityNVIC priority accepted by ra8_isr_register.
Returns
Error code.
Return values
k_ra8_okInterrupt delivery enabled.
k_ra8_err_null_ptrcallback was nullptr.
k_ra8_err_invalid_argChannel or priority is invalid.
k_ra8_err_existsThe channel is already streaming.
otherPropagated ISR registration error.
Precondition
ra8_pdm_read_enable and ra8_isr_init succeeded.
Postcondition
Each FIFO threshold invokes callback from interrupt context.
Note
Not thread-safe. One stream may be active per PDM channel.
Since
0.1.0

Definition at line 294 of file ra8_pdm.c.

References internal_pdm_data_isr(), k_ra8_err_exists, k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_pdm_ch_count, k_ra8_pdm_pdicr_idre, r_pdm_ch_regs_t::PDICR, RA8_CHECK_NULL_PTR, RA8_CHECK_RANGE_TAG, ra8_isr_register(), ra8_pdm_ch(), s_pdm_data_events, s_streams, and s_tag.

Referenced by internal_pdm_stream_start().

Variable Documentation

◆ s_pdm_data_events

const ra8_elc_event_t s_pdm_data_events[k_ra8_pdm_ch_count]
static
Initial value:
= {
}
@ k_ra8_elc_event_pdm_dat0
PDM channel 0 data reception.
@ k_ra8_elc_event_pdm_dat1
PDM channel 1 data reception.
@ k_ra8_elc_event_pdm_dat2
PDM channel 2 data reception.

Definition at line 43 of file ra8_pdm.c.

Referenced by ra8_pdm_stream_disable(), and ra8_pdm_stream_enable().

◆ s_streams

◆ s_tag

const char* s_tag = "PDM"
static

Definition at line 33 of file ra8_pdm.c.