ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_pdm.c
Go to the documentation of this file.
1
19
20#include "ra8_pdm.h"
21
22#include <stdint.h>
23
24#include "ra8_attributes.h"
25#include "ra8_check.h"
26#include "ra8_err.h"
27#include "ra8_isr.h"
28#include "ra8_log.h"
29#include "ra8_mstp.h"
30#include "ra8_mstp_regs.h"
31#include "ra8_pdm_regs.h"
32
33static const char* s_tag = "PDM";
34
40
42
48
53typedef enum : uint32_t {
58
81 const ra8_pdm_channel_cfg_t* cfg)
82{
83 uint32_t pdmdsr = (uint32_t)(cfg->edge & (uint8_t)k_ra8_pdm_pdmdsr_inpsel);
84 pdmdsr |= ((uint32_t)cfg->sinc_order & k_pdm_field_3bit) << k_ra8_pdm_pdmdsr_sfmd_pos;
85 pdmdsr |= (uint32_t)cfg->hpf_shift << k_ra8_pdm_pdmdsr_hfis_pos;
86 pdmdsr |= (uint32_t)cfg->cf_shift << k_ra8_pdm_pdmdsr_cfis_pos;
87 pdmdsr |= (uint32_t)cfg->lpf_shift << k_ra8_pdm_pdmdsr_lfis_pos;
88 pdmdsr |= (uint32_t)cfg->data_shift << k_ra8_pdm_pdmdsr_dbis_pos;
89 /* HUM Ch 49.2.19 "PDMDSRCHn : Mode Setting Register" p 3208 */
90 reg->PDMDSR = pdmdsr;
91
92 uint32_t pdsfcr = (uint32_t)cfg->clock_div << k_ra8_pdm_pdsfcr_ckdiv_pos;
93 pdsfcr |= (uint32_t)cfg->sinc_dec << k_ra8_pdm_pdsfcr_sincdec_pos;
94 pdsfcr |= (uint32_t)cfg->sinc_range << k_ra8_pdm_pdsfcr_sincrng_pos;
95 /* HUM Ch 49.2.20 "PDSFCRCHn : Sinc Filter Control Register" p 3210 */
96 reg->PDSFCR = pdsfcr;
97}
98
121 const ra8_pdm_channel_cfg_t* cfg)
122{
123 /* HUM Ch 49.2 "Filter coefficient registers" p 3210 */
124 reg->PDHFCS0R = (uint32_t)cfg->hpf_s0;
125 reg->PDHFCK1R = (uint32_t)cfg->hpf_k1;
126 for (uint8_t i = 0U; i < (uint8_t)k_ra8_pdm_hpf_h_count; ++i) {
127 /* HUM Ch 49.2 "PDHFCHnRCHn : High-pass filter Coefficient" p 3211 */
128 reg->PDHFCHR[i] = (uint32_t)cfg->hpf_h[i];
129 }
130 for (uint8_t i = 0U; i < (uint8_t)k_ra8_pdm_comp_h_count; ++i) {
131 /* HUM Ch 49.2 "PDCFCHnnRCHn : Compensation filter Coefficient" p 3213 */
132 reg->PDCFCHR[i] = (uint32_t)cfg->comp_h[i];
133 }
134 /* HUM Ch 49.2 "PDLFCH010RCHn : Low-pass filter Coefficient h0(10)" p 3216 */
135 reg->PDLFCH010R = (uint32_t)cfg->lpf_h0;
136 for (uint8_t i = 0U; i < (uint8_t)k_ra8_pdm_lpf_h1_count; ++i) {
137 /* HUM Ch 49.2 "PDLFCH1nnRCHn : Low-pass filter Coefficient h1" p 3218 */
138 reg->PDLFCH1R[i] = (uint32_t)cfg->lpf_h1[i];
139 }
140}
141
164RA8_INTERNAL static int32_t internal_pdm_sign_extend20(uint32_t raw)
165{
166 const uint32_t dat = raw & (uint32_t)k_ra8_pdm_pddrr_dat_mask;
167 if ((dat & (uint32_t)k_ra8_pdm_pddrr_sign_bit) != 0U) {
168 return (int32_t)(dat | (uint32_t)k_ra8_pdm_pddrr_sign_ext);
169 }
170 return (int32_t)dat;
171}
172
186{
187 const uint8_t channel = (uint8_t)(uintptr_t)ctx;
188 if (channel >= (uint8_t)k_ra8_pdm_ch_count) {
189 return;
190 }
191 pdm_stream_state_t* stream = &s_streams[channel];
192 if (stream->callback == nullptr) {
193 return;
194 }
195 volatile const r_pdm_ch_regs_t* reg = ra8_pdm_ch(channel);
196 /* HUM Ch 49.2.66 "PDDSRCHn : Data Status Register" p 3228 */
197 uint32_t count = reg->PDDSR & (uint32_t)k_ra8_pdm_pddsr_num_mask;
198 if (count > (uint32_t)k_ra8_pdm_fifo_depth) {
199 count = (uint32_t)k_ra8_pdm_fifo_depth;
200 }
201 int32_t samples[k_ra8_pdm_fifo_depth];
202 for (uint32_t i = 0U; i < count; ++i) {
203 /* HUM Ch 49.2.65 "PDDRRCHn : Data Read Register" p 3227 */
204 samples[i] = internal_pdm_sign_extend20(reg->PDDRR);
205 }
206 if (count != 0U) {
207 stream->callback(stream->ctx, samples, count);
208 }
209}
210
212{
214 RA8_RETURN_ON_ERROR(mst_err, s_tag, "pdm_init: mstp enable");
215
216 volatile r_pdm_regs_t* reg = ra8_pdm();
217 /* HUM Ch 49.2.4 "PDCICR : Channel Interrupt Control Register" p 3198 */
218 reg->PDCICR = 0U;
219 /* HUM Ch 49.2.9 "PDCDRCR : Channel Data Read Control Register" p 3202 */
220 reg->PDCDRCR = 0U;
221 ra8_log_info(s_tag, "pdm_init");
222 return k_ra8_ok;
223}
224
226{
227 volatile r_pdm_regs_t* reg = ra8_pdm();
228 /* HUM Ch 49.2.9 "PDCDRCR : Channel Data Read Control Register" p 3202 */
229 reg->PDCDRCR = 0U;
231}
232
234{
235 RA8_CHECK_NULL_PTR(cfg, s_tag, "cfg must not be nullptr");
237
238 volatile r_pdm_ch_regs_t* reg = ra8_pdm_ch(ch);
239 internal_pdm_write_mode(reg, cfg);
241 /* HUM Ch 49.2.59 "PDDBCRCHn : Data Buffer Control Register" p 3225 */
242 reg->PDDBCR = (uint32_t)cfg->rx_threshold;
243 return k_ra8_ok;
244}
245
247{
249 /* HUM Ch 49.2.2 "PDCSTRTR : Channel Software Start Trigger Register" p 3196 */
250 ra8_pdm()->PDCSTRTR = (uint32_t)k_ra8_pdm_pdstrtr_strt << ch;
251 return k_ra8_ok;
252}
253
255{
257
258 volatile r_pdm_ch_regs_t* reg = ra8_pdm_ch(ch);
259 /* HUM Ch 49.2.18 "PDSCRCHn : Status Clear Register" p 3208 */
260 reg->PDSCR = (uint32_t)k_ra8_pdm_pdscr_clr_all;
261 /* HUM Ch 49.2.63 "PDDRCRCHn : Data Read Control Register" p 3227 */
262 reg->PDDRCR = (uint32_t)k_ra8_pdm_pddrcr_datre;
263 /* Prime the FIFO: discard the first (depth - 2) reads before valid data. */
264 for (uint32_t i = 0U; i < (uint32_t)k_pdm_prime_discards; ++i) {
265 /* HUM Ch 49.2.65 "PDDRRCHn : Data Read Register" p 3227 */
266 (void)reg->PDDRR;
267 }
268 return k_ra8_ok;
269}
270
271ra8_err_t ra8_pdm_read(uint8_t ch, int32_t* out, uint32_t max, uint32_t* out_count)
272{
273 RA8_CHECK_NULL_PTR(out, s_tag, "out must not be nullptr");
274 RA8_CHECK_NULL_PTR(out_count, s_tag, "out_count must not be nullptr");
276 if (max == 0U) {
277 ra8_log_error(s_tag, "read: max must be > 0");
279 }
280
281 volatile const r_pdm_ch_regs_t* reg = ra8_pdm_ch(ch);
282 /* HUM Ch 49.2.66 "PDDSRCHn : Data Status Register" p 3228 */
283 const uint32_t avail = reg->PDDSR & (uint32_t)k_ra8_pdm_pddsr_num_mask;
284 const uint32_t n = (avail < max) ? avail : max;
285 for (uint32_t i = 0U; i < n; ++i) {
286 /* HUM Ch 49.2.65 "PDDRRCHn : Data Read Register" p 3227 */
287 out[i] = internal_pdm_sign_extend20(reg->PDDRR);
288 }
289 *out_count = n;
290 return k_ra8_ok;
291}
292
294ra8_pdm_stream_enable(uint8_t ch, ra8_pdm_data_callback_t callback, void* ctx, uint8_t priority)
295{
296 RA8_CHECK_NULL_PTR(callback, s_tag, "callback must not be nullptr");
298 if (s_streams[ch].callback != nullptr) {
299 return k_ra8_err_exists;
300 }
301 s_streams[ch] = (pdm_stream_state_t){.callback = callback, .ctx = ctx};
304 (void*)(uintptr_t)ch,
305 priority,
306 nullptr);
307 if (err != k_ra8_ok) {
309 return err;
310 }
311 /* HUM Ch 49.2.15 "PDICRCHn : Interrupt Control Register" p 3205 */
312 ra8_pdm_ch(ch)->PDICR |= (uint32_t)k_ra8_pdm_pdicr_idre;
313 return k_ra8_ok;
314}
315
317{
319 if (s_streams[ch].callback == nullptr) {
321 }
322 /* HUM Ch 49.2.15 "PDICRCHn : Interrupt Control Register" p 3205 */
323 ra8_pdm_ch(ch)->PDICR &= ~(uint32_t)k_ra8_pdm_pdicr_idre;
325 if (err != k_ra8_ok) {
326 return err;
327 }
329 return k_ra8_ok;
330}
331
333{
335
336 if (s_streams[ch].callback != nullptr) {
337 const ra8_err_t stream_err = ra8_pdm_stream_disable(ch);
338 RA8_RETURN_ON_ERROR(stream_err, s_tag, "pdm_stop: stream disable");
339 }
340
341 /* HUM Ch 49.2.63 "PDDRCRCHn : Data Read Control Register" p 3227 */
342 ra8_pdm_ch(ch)->PDDRCR = 0U;
343 /* HUM Ch 49.2.3 "PDCSTPTR : Channel Software Stop Trigger Register" p 3197 */
344 ra8_pdm()->PDCSTPTR = (uint32_t)k_ra8_pdm_pdstptr_stp << ch;
345
346 const uint32_t running = (uint32_t)k_ra8_pdm_pdsr_state << ch;
347 for (uint32_t i = 0U; i < (uint32_t)k_pdm_stop_poll_max; ++i) {
348 /* HUM Ch 49.2.6 "PDCSR : Channel Status Register" p 3199 */
349 if ((ra8_pdm()->PDCSR & running) == 0U) {
350 return k_ra8_ok;
351 }
352 }
353 ra8_log_error(s_tag, "stop: channel did not halt");
355}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
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_RANGE_TAG(value, min, max, errcode, tag)
Tagged range check (adds a component tag to the log line).
Definition ra8_check.h:311
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
ra8_elc_event_t
Partial list of ELC events (populate as drivers need them).
@ 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.
Error Code Definitions for ra8-firmware.
@ 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
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
NVIC + ICU IELSR allocator.
ra8_err_t ra8_isr_register(ra8_elc_event_t event, ra8_isr_handler_t handler, void *ctx, uint8_t priority, uint16_t *out_slot)
Allocate an IELSR slot for an ELC event + handler.
Definition ra8_isr.c:296
ra8_err_t ra8_isr_unregister(ra8_elc_event_t event)
Release a previously-allocated IELSR slot.
Definition ra8_isr.c:335
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info(tag, message)
RA8 log info.
Definition ra8_log.h:364
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
Ref-counted Module Stop Control wrapper for the RA8D2.
ra8_err_t ra8_mstp_enable(ra8_mstp_t id)
Reference-counted "ungate this peripheral" request.
Definition ra8_mstp.c:343
ra8_err_t ra8_mstp_disable(ra8_mstp_t id)
Reference-counted "gate this peripheral" request.
Definition ra8_mstp.c:382
Module Stop Control (MSTP) register layout for the Renesas RA8D2.
@ k_ra8_mstp_pdmif
MSTPC24 PDM-IF.
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
static void internal_pdm_data_isr(void *ctx)
Drain one PDM FIFO threshold and dispatch its signed samples.
Definition ra8_pdm.c:185
static pdm_stream_state_t s_streams[k_ra8_pdm_ch_count]
Definition ra8_pdm.c:41
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
static const ra8_elc_event_t s_pdm_data_events[k_ra8_pdm_ch_count]
Definition ra8_pdm.c:43
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
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.
Definition ra8_pdm.c:80
static int32_t internal_pdm_sign_extend20(uint32_t raw)
Sign-extend one 20-bit PDDRR sample to a full int32_t.
Definition ra8_pdm.c:164
ra8_err_t ra8_pdm_stream_disable(uint8_t ch)
Disable interrupt-driven delivery for one channel.
Definition ra8_pdm.c:316
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
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.
Definition ra8_pdm.c:120
pdm_impl_const_t
Implementation-local bounds (HUM Ch 49 "Normal Processing Flow").
Definition ra8_pdm.c:53
@ k_pdm_prime_discards
FIFO depth (32) minus 2 priming reads.
Definition ra8_pdm.c:54
@ k_pdm_field_3bit
3-bit field mask (SFMD).
Definition ra8_pdm.c:56
@ k_pdm_stop_poll_max
Bounded stop-poll retry budget.
Definition ra8_pdm.c:55
Pulse Density Modulation Interface (PDM-IF) capture driver.
void(* ra8_pdm_data_callback_t)(void *ctx, const int32_t *samples, uint32_t count)
PDM FIFO data callback invoked from ICU interrupt context.
Definition ra8_pdm.h:123
@ k_ra8_pdm_hpf_h_count
High-pass filter h(0..1) coefficients.
Definition ra8_pdm.h:72
@ k_ra8_pdm_comp_h_count
Compensation filter h(0..10) coefficients.
Definition ra8_pdm.h:73
@ k_ra8_pdm_lpf_h1_count
Low-pass (half-band) h1(0..19) coefficients.
Definition ra8_pdm.h:74
@ k_ra8_pdm_ch_count
Number of channels (bound).
Definition ra8_pdm.h:60
Pulse Density Modulation Interface (PDM-IF) register layout.
static volatile r_pdm_regs_t * ra8_pdm(void)
Get a pointer to the PDM-IF register block.
@ k_ra8_pdm_pdscr_clr_all
PDSCR clear-all write pattern.
@ k_ra8_pdm_pdstptr_stp
PDSTPTR[0] stop trigger.
@ k_ra8_pdm_pddrcr_datre
PDDRCR[0] data read enable.
@ k_ra8_pdm_pdsr_state
PDSR[0] channel running.
@ k_ra8_pdm_pdstrtr_strt
PDSTRTR[0] start trigger.
@ k_ra8_pdm_pdicr_idre
PDICR[2] data IRQ enable.
@ k_ra8_pdm_pdmdsr_hfis_pos
[9:8] High-pass input shift.
@ k_ra8_pdm_pdmdsr_dbis_pos
[31:28] Data buffer input shift.
@ k_ra8_pdm_pdmdsr_lfis_pos
[17:16] Low-pass input shift.
@ k_ra8_pdm_pdmdsr_sfmd_pos
[6:4] Sinc filter mode shift.
@ k_ra8_pdm_pdmdsr_inpsel
[0] Input data edge select.
@ k_ra8_pdm_pdmdsr_cfis_pos
[13:12] Compensation input shift.
@ k_ra8_pdm_pddrr_dat_mask
PDDRR[19:0] 20-bit PCM.
@ k_ra8_pdm_pddrr_sign_ext
High bits set on negatives.
@ k_ra8_pdm_pddrr_sign_bit
PDDRR[19] sign bit.
@ k_ra8_pdm_pddsr_num_mask
PDDSR[7:0] FIFO fill count.
static volatile r_pdm_ch_regs_t * ra8_pdm_ch(uint8_t ch)
Get a pointer to a PDM-IF channel register bank.
@ k_ra8_pdm_fifo_depth
PDDRR FIFO depth (samples).
@ k_ra8_pdm_pdsfcr_ckdiv_pos
[3:0] PDM_CLKn dividend ratio.
@ k_ra8_pdm_pdsfcr_sincrng_pos
[28:24] Sinc output valid range.
@ k_ra8_pdm_pdsfcr_sincdec_pos
[23:16] Sinc decimation ratio.
Per-channel interrupt callback binding.
Definition ra8_pdm.c:36
void * ctx
Caller context.
Definition ra8_pdm.c:38
ra8_pdm_data_callback_t callback
Caller callback.
Definition ra8_pdm.c:37
Per-channel PDM-IF register bank (256 bytes, HUM Ch 49.2).
volatile uint32_t PDICR
+0x0C Interrupt Control.
volatile uint32_t PDDSR
+0xEC Data Status (FIFO fill count).
volatile uint32_t PDLFCH1R[k_ra8_pdm_lfch1_count]
+0x68 Low-pass filter coeff h1(0..19).
volatile uint32_t PDDBCR
+0xC0 Data Buffer Control.
volatile uint32_t PDDRCR
+0xE0 Data Read Control.
volatile uint32_t PDSFCR
+0x24 Sinc Filter Control.
volatile uint32_t PDDRR
+0xE8 Data Read (20-bit PCM out).
volatile uint32_t PDHFCHR[2]
+0x30 High-pass filter coeff h(0..1).
volatile uint32_t PDSCR
+0x18 Status Clear.
volatile uint32_t PDCFCHR[k_ra8_pdm_cfch_count]
+0x38 Comp filter coeff h(0..10).
volatile uint32_t PDHFCS0R
+0x28 High-pass filter coeff s(0).
volatile uint32_t PDLFCH010R
+0x64 Low-pass filter coeff h0(10).
volatile uint32_t PDHFCK1R
+0x2C High-pass filter coeff k(1).
volatile uint32_t PDMDSR
+0x20 Mode Setting.
Full PDM-IF register block: common bank + 3 channel banks.
volatile uint32_t PDCSTRTR
+0x00 Channel Software Start Trigger.
volatile uint32_t PDCDRCR
+0x24 Channel Data Read Control.
volatile uint32_t PDCICR
+0x0C Channel Interrupt Control.
volatile uint32_t PDCSTPTR
+0x04 Channel Software Stop Trigger.
One PDM channel's mode + filter configuration.
Definition ra8_pdm.h:93
uint16_t lpf_h0
Low-pass filter coefficient h0.
Definition ra8_pdm.h:108
uint16_t hpf_h[k_ra8_pdm_hpf_h_count]
High-pass filter h(0..1).
Definition ra8_pdm.h:106
uint16_t comp_h[k_ra8_pdm_comp_h_count]
Compensation filter h(0..10).
Definition ra8_pdm.h:107
uint16_t lpf_h1[k_ra8_pdm_lpf_h1_count]
Low-pass filter h1(0..19).
Definition ra8_pdm.h:109
uint8_t hpf_shift
High-pass input shift (PDMDSR.HFIS[1:0]).
Definition ra8_pdm.h:100
uint8_t rx_threshold
Data reception threshold code (PDDBCR.DATRITHR).
Definition ra8_pdm.h:103
uint16_t hpf_k1
High-pass filter coefficient k(1).
Definition ra8_pdm.h:105
uint8_t sinc_order
Sinc filter order 1..4 (PDMDSR.SFMD).
Definition ra8_pdm.h:94
uint8_t data_shift
Data-buffer input shift (PDMDSR.DBIS[3:0]).
Definition ra8_pdm.h:98
uint8_t clock_div
PDM_CLKn divider code (PDSFCR.CKDIV[3:0]).
Definition ra8_pdm.h:95
uint8_t lpf_shift
Low-pass input shift (PDMDSR.LFIS[1:0]).
Definition ra8_pdm.h:102
uint8_t cf_shift
Compensation input shift (PDMDSR.CFIS[1:0]).
Definition ra8_pdm.h:101
uint8_t sinc_dec
Sinc decimation ratio - 1 (PDSFCR.SINCDEC[7:0]).
Definition ra8_pdm.h:96
uint8_t sinc_range
Sinc output clip range (PDSFCR.SINCRNG[4:0]).
Definition ra8_pdm.h:97
uint8_t edge
0: rise-edge ch n; 1: fall-edge ch n-1 (INPSEL).
Definition ra8_pdm.h:99
uint16_t hpf_s0
High-pass filter coefficient s(0).
Definition ra8_pdm.h:104