PDM/PCM (Pulse-Density Modulation to Pulse-Code Modulation Converter)¶
-
group
group_hal_pdmpcm
-
High level interface for interacting with the pulse-density modulation to pulse-code modulation (PDM/PCM) converter.
The PDM/PCM converter is a asynchronous operation. A PDM-PCM converter is used to convert 1-bit digital audio streaming data to PCM data. The sample rate, word size, and channels can all be configured.
Features
Supports FIFO buffer for Incoming Data
Configurable Gain Settings
Configurable Word Length
Configurable interrupt and callback assignment from PDM/PCM events - cyhal_pdm_pcm_event_t
Quick Start
Initialize a PDM/PCM converter instance using the cyhal_pdm_pcm_init
and provide the clock and data pins.
See
Snippet 1: PDM/PCM Initialization and Configuration for example initialization.note
The clock parameter (const cyhal_clock_t *clk) is optional and can be set to NULL to generate and use an available clock resource with a default frequency.
Code Snippets
note
Error checking is omitted for clarity
Snippet 1: PDM/PCM Initialization and Configuration
This snippet initializes a PCM/PCM resource for conversion and assigns the pins.
cyhal_pdm_pcm_t pdm_pcm; cyhal_pdm_pcm_cfg_t cfg = { .sample_rate = 44000, .decimation_rate = 10, .mode = CYHAL_PDM_PCM_MODE_STEREO, .word_length = 16, .left_gain = 1, // +0.5 db gain .right_gain = -2, // -1.0 db gain }; cy_rslt_t result = cyhal_pdm_pcm_init(&pdm_pcm, P0_5, P0_4, NULL, &cfg); CY_ASSERT(CY_RSLT_SUCCESS == result); // When the PDM/PCM instance is no longer required, free it to release resources cyhal_pdm_pcm_free(&pdm_pcm);
Snippet 2: PDM/PCM Asynchronous Receive
This snippet shows how to receive data in the background using cyhal_pdm_pcm_read_async. Notification of the asynchronous read completion is achieved by using cyhal_pdm_pcm_register_callback to register a callback function and cyhal_pdm_pcm_enable_event to enable callling the callback when an synchonous read completes.
// We use a dual buffer system so that one buffer can be filling while the other is being processed #define BUFFER_SIZE 128u static uint32_t rx_buffer0[BUFFER_SIZE]; static uint32_t rx_buffer1[BUFFER_SIZE]; static uint32_t* active_rx_buffer; static uint32_t* full_rx_buffer; static void pdm_pcm_event_handler(void* arg, cyhal_pdm_pcm_event_t event) { // When we registered the callback, we set 'arg' to point to the pdm_pcm object cyhal_pdm_pcm_t* pdm_pcm = (cyhal_pdm_pcm_t*)arg; if (0u != (event & CYHAL_PDM_PCM_ASYNC_COMPLETE)) { // Flip the active and the next rx buffers uint32_t* temp = active_rx_buffer; active_rx_buffer = full_rx_buffer; full_rx_buffer = temp; // Start reading into the next buffer while the just-filled one is being processed cy_rslt_t result = cyhal_pdm_pcm_read_async(pdm_pcm, active_rx_buffer, BUFFER_SIZE); CY_ASSERT(CY_RSLT_SUCCESS == result); // Process the data in the full_rx_buffer } } void snippet_cyhal_pdm_pcm_async_receive(void) { cyhal_pdm_pcm_t pdm_pcm; // Initialize the object as shown in Snippet 1 // Register a callback and set the callback argument to be a pointer to the PDM/PCM object, so // that we can easily reference it from the callback handler. cyhal_pdm_pcm_register_callback(&pdm_pcm, &pdm_pcm_event_handler, &pdm_pcm); // Subscribe to the async complete event so that we can queue up another transfer when this one // completes cyhal_pdm_pcm_enable_event(&pdm_pcm, CYHAL_PDM_PCM_ASYNC_COMPLETE, CYHAL_ISR_PRIORITY_DEFAULT, true); // Configure asynchronous transfers to use DMA to free up the CPU during transfers cy_rslt_t result = cyhal_pdm_pcm_set_async_mode(&pdm_pcm, CYHAL_ASYNC_DMA, CYHAL_DMA_PRIORITY_DEFAULT); CY_ASSERT(CY_RSLT_SUCCESS == result); active_rx_buffer = rx_buffer0; full_rx_buffer = rx_buffer1; result = cyhal_pdm_pcm_read_async(&pdm_pcm, active_rx_buffer, BUFFER_SIZE); result = cyhal_pdm_pcm_start(&pdm_pcm); }
More Information
Code examples (Github)
Typedefs
-
typedef void (*
cyhal_pdm_pcm_event_callback_t
)(void *handler_arg, cyhal_pdm_pcm_event_t event)¶ Handler for PDM/PCM interrupts.
Enums
-
enum
cyhal_pdm_pcm_event_t
¶ cyhal_pdm_pcm_event_t: PDM/PCM interrupt triggers.
Values:
-
enumerator
CYHAL_PDM_PCM_RX_HALF_FULL
¶ RX hardware buffer is half full.
-
enumerator
CYHAL_PDM_PCM_RX_NOT_EMPTY
¶ RX hardware buffer is not empty.
-
enumerator
CYHAL_PDM_PCM_RX_OVERFLOW
¶ Attempt to write to a full RX hardware buffer.
-
enumerator
CYHAL_PDM_PCM_RX_UNDERFLOW
¶ Attempt to read from an empty buffer.
-
enumerator
CYHAL_PDM_PCM_ASYNC_COMPLETE
¶ Async operation completed.
-
enumerator
Functions
-
cy_rslt_t
cyhal_pdm_pcm_init
(cyhal_pdm_pcm_t *obj, cyhal_gpio_t pin_data, cyhal_gpio_t pin_clk, const cyhal_clock_t *clk_source, const cyhal_pdm_pcm_cfg_t *cfg)¶ Initialize the PDM/PCM peripheral.
Configures the pins used by PDM/PCM converter, sets a default format and frequency, and enables the peripheral
- Parameters
obj – [out] Pointer to a PDM/PCM object. The caller must allocate the memory for this object but the init function will initialize its contents.
pin_data – [in] The pin to use for PDM input
pin_clk – [in] The pin to use for PDM clock output
clk_source – [in] The clock source for PDM/PCM block
cfg – [in] The configuration for the PDM/PCM block
- Returns
The status of the init request
-
void
cyhal_pdm_pcm_free
(cyhal_pdm_pcm_t *obj)¶ Release a PDM/PCM object, behavior is undefined if an asynchronous read is in progress.
Return the peripheral, pins and clock owned by the PDM/PCM object to their reset state
- Parameters
obj – [inout] The PDM/PCM object to deinitialize
-
cy_rslt_t
cyhal_pdm_pcm_start
(cyhal_pdm_pcm_t *obj)¶ Start the PDM/PCM operation.
- Parameters
obj – [in] The PDM/PCM object to start
- Returns
the status of the start request
-
cy_rslt_t
cyhal_pdm_pcm_stop
(cyhal_pdm_pcm_t *obj)¶ Stop the PDM/PCM operation.
- Parameters
obj – [in] The PDM/PCM object to start
- Returns
the status of the stop request
-
bool
cyhal_pdm_pcm_is_enabled
(cyhal_pdm_pcm_t *obj)¶ Checks if the specified PDM/PCM peripheral is enabled (regardless of whether any unread data has been received).
The PDM/PCM peripheral can be enabled by calling cyhal_pdm_pcm_start and disabled by calling cyhal_pdm_pcm_stop
- Parameters
obj – [in] The I2S peripheral to check
- Returns
Whether the I2S receive function is enabled.
-
cy_rslt_t
cyhal_pdm_pcm_set_gain
(cyhal_pdm_pcm_t *obj, int8_t gain_left, int8_t gain_right)¶ Updates the PDM/PCM channel gains.
Each integer increment represent a 0.5 dB value. For example: a gain value of 5 would mean +2.5 dB. If the exact gain value requested is not supported, it will be rounded to the nearest legal value. See the implementation specific documentation for valid ranges.
note
Gains may be negative if the implementation supports it.
- Parameters
obj – [in] The PDM/PCM object to configure
gain_left – [in] The gain of the left channel in units of 0.5 dB
gain_right – [in] The gain of the right channel in units of 0.5 dB
- Returns
The status of the set gain operation. An error will be returned if the value is outside of range supported by HW.
-
cy_rslt_t
cyhal_pdm_pcm_clear
(cyhal_pdm_pcm_t *obj)¶ Clears the hardware buffer.
- Parameters
obj – [in] The PDM/PCM peripheral
- Returns
The status of the clear request
-
cy_rslt_t
cyhal_pdm_pcm_read
(cyhal_pdm_pcm_t *obj, void *data, size_t *length)¶ Reads data synchronously.
This will read either length words or the number of words that are currently available in the receive buffer, whichever is less, then return. The value pointed to by length will be updated to reflect the number of words that were actually read. If there are less data in FIFO than length, length will be update with number of words read.
- Parameters
obj – [in] The PDM/PCM peripheral
data – [out] Pointer to word array where incoming data will be stored. Buffer must be aligned to word-size. Each word will be aligned to the next largest power of 2. For example, if the word length is 16 bits, each word will consume two bytes. But if the word length is 20, each word will consume 32 bits. Negative value will use sign-extension. -1 with 24-bit word length will have 32-bit value of 0xFFFFFFFF.
length – [inout] Number of 32-bit words to read, updated with the number actually read
- Returns
The status of the read request
-
cy_rslt_t
cyhal_pdm_pcm_read_async
(cyhal_pdm_pcm_t *obj, void *data, size_t length)¶ Begin asynchronous PDM/PCM read.
This will transfer length words into the buffer pointed to by data in the background. When the requested quantity of data has been read, the CYHAL_PDM_PCM_ASYNC_COMPLETE event will be raised. See cyhal_pdm_pcm_register_callback and cyhal_pdm_pcm_enable_event.
cyhal_pdm_pcm_set_async_mode can be used to control whether this uses DMA or a CPU-driven transfer.
- Parameters
obj – [in] The PDM/PCM object
data – [out] Pointer to word array where incoming data will be stored. Buffer must be aligned to word-size. Each word will be aligned to the next largest power of 2. For example, if the word length is 16 bits, each word will consume two bytes. But if the word length is 20, each word will consume 32 bits. Negative value will use sign-extension. -1 with 24-bit word length will have 32-bit value of 0xFFFFFFFF.
length – [in] Number of words to read
- Returns
The status of the read_async request
-
bool
cyhal_pdm_pcm_is_pending
(cyhal_pdm_pcm_t *obj)¶ Checks if an async read operation is pending.
- Parameters
obj – [in] The PDM/PCM peripheral to check
- Returns
Indication of whether a PDM/PCM async operation is pending
-
cy_rslt_t
cyhal_pdm_pcm_abort_async
(cyhal_pdm_pcm_t *obj)¶ Abort an PDM/PCM operation started by cyhal_pdm_pcm_read_async function.
- Parameters
obj – [in] The PDM/PCM peripheral to stop
- Returns
The status of the abort_async request
-
void
cyhal_pdm_pcm_register_callback
(cyhal_pdm_pcm_t *obj, cyhal_pdm_pcm_event_callback_t callback, void *callback_arg)¶ Register a PDM/PCM event handler.
This function will be called when one of the events enabled by cyhal_pdm_pcm_enable_event occurs.
- Parameters
obj – [in] The PDM/PCM object
callback – [in] The callback handler which will be invoked when the interrupt fires
callback_arg – [in] Generic argument that will be provided to the callback when called
-
void
cyhal_pdm_pcm_enable_event
(cyhal_pdm_pcm_t *obj, cyhal_pdm_pcm_event_t event, uint8_t intr_priority, bool enable)¶ Configure PDM/PCM event enablement.
- Parameters
obj – [in] The PDM/PCM object
event – [in] The PDM/PCM event type
intr_priority – [in] The priority for NVIC interrupt events
enable – [in] True to turn on events, False to turn off
-
cy_rslt_t
cyhal_pdm_pcm_set_async_mode
(cyhal_pdm_pcm_t *obj, cyhal_async_mode_t mode, uint8_t dma_priority)¶ Set the mechanism that is used to perform PDM/PCM asynchronous operation.
The default is SW.
When an enabled event occurs, the function specified by cyhal_pdm_pcm_register_callback will be called.
- Parameters
obj – [in] The PDM/PCM object
mode – [in] The transfer mode
dma_priority – [in] The priority, if DMA is used. Valid values are the same as for cyhal_dma_init. If DMA is not selected, the only valid value is CYHAL_DMA_PRIORITY_DEFAULT, and no guarantees are made about prioritization.
- Returns
The status of the set mode request
-
struct
cyhal_pdm_pcm_cfg_t
¶ - #include <>
Describes the current configuration of a PDM/PCM.
Public Members
-
uint32_t
sample_rate
¶ Sample rate in Hz.
-
uint8_t
decimation_rate
¶ PDM decimation rate.
-
cyhal_pdm_pcm_mode_t
mode
¶ left, right, or stereo
-
uint8_t
word_length
¶ PCM word length in bits, see the implementation specific documentation for valid range.
-
int8_t
left_gain
¶ PGA in 0.5 dB increment, for example a value of 5 would mean +2.5 dB.
The closest fit value will be used, see the implementation specific documentation for valid ranges. This may be negative if the implementation supports it.
-
int8_t
right_gain
¶ PGA in 0.5 dB increment, for example a value of 5 would mean +2.5 dB.
The closest fit value will be used, see the implementation specific documentation for valid ranges. This may be negative if the implementation supports it.
-
uint32_t