Hardware Abstraction Layer (HAL)
PDM/PCM (Pulse-Density Modulation to Pulse-Code Modulation Converter)

General Description


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

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;
{
.sample_rate = 44000,
.decimation_rate = 10,
.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 */
/* Configure asynchronous transfers to use DMA to free up the CPU during transfers */
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)

API Reference

 PDM/PCM HAL Results
 PDM/PCM specific return codes.
 

Data Structures

struct  cyhal_pdm_pcm_cfg_t
 Describes the current configuration of a PDM/PCM. More...
 

Typedefs

typedef void(* cyhal_pdm_pcm_event_callback_t) (void *handler_arg, cyhal_pdm_pcm_event_t event)
 Handler for PDM/PCM interrupts.
 

Enumerations

enum  cyhal_pdm_pcm_event_t {
  CYHAL_PDM_PCM_RX_HALF_FULL = 0x01,
  CYHAL_PDM_PCM_RX_NOT_EMPTY = 0x02,
  CYHAL_PDM_PCM_RX_OVERFLOW = 0x04,
  CYHAL_PDM_PCM_RX_UNDERFLOW = 0x08,
  CYHAL_PDM_PCM_ASYNC_COMPLETE = 0x10
}
 PDM/PCM interrupt triggers. More...
 
enum  cyhal_pdm_pcm_mode_t {
  CYHAL_PDM_PCM_MODE_LEFT,
  CYHAL_PDM_PCM_MODE_RIGHT,
  CYHAL_PDM_PCM_MODE_STEREO
}
 PDM/PCM channel select. More...
 

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. More...
 
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. More...
 
cy_rslt_t cyhal_pdm_pcm_start (cyhal_pdm_pcm_t *obj)
 Start the PDM/PCM operation. More...
 
cy_rslt_t cyhal_pdm_pcm_stop (cyhal_pdm_pcm_t *obj)
 Stop the PDM/PCM operation. More...
 
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). More...
 
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. More...
 
cy_rslt_t cyhal_pdm_pcm_clear (cyhal_pdm_pcm_t *obj)
 Clears the hardware buffer. More...
 
cy_rslt_t cyhal_pdm_pcm_read (cyhal_pdm_pcm_t *obj, void *data, size_t *length)
 Reads data synchronously. More...
 
cy_rslt_t cyhal_pdm_pcm_read_async (cyhal_pdm_pcm_t *obj, void *data, size_t length)
 Begin asynchronous PDM/PCM read. More...
 
bool cyhal_pdm_pcm_is_pending (cyhal_pdm_pcm_t *obj)
 Checks if an async read operation is pending. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 

Data Structure Documentation

◆ cyhal_pdm_pcm_cfg_t

struct cyhal_pdm_pcm_cfg_t
Data Fields
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.

Enumeration Type Documentation

◆ cyhal_pdm_pcm_event_t

PDM/PCM interrupt triggers.

Enumerator
CYHAL_PDM_PCM_RX_HALF_FULL 

RX hardware buffer is half full.

CYHAL_PDM_PCM_RX_NOT_EMPTY 

RX hardware buffer is not empty.

CYHAL_PDM_PCM_RX_OVERFLOW 

Attempt to write to a full RX hardware buffer.

CYHAL_PDM_PCM_RX_UNDERFLOW 

Attempt to read from an empty buffer.

CYHAL_PDM_PCM_ASYNC_COMPLETE 

Async operation completed.

◆ cyhal_pdm_pcm_mode_t

PDM/PCM channel select.

Enumerator
CYHAL_PDM_PCM_MODE_LEFT 

The channel mono left.

CYHAL_PDM_PCM_MODE_RIGHT 

The channel mono right.

CYHAL_PDM_PCM_MODE_STEREO 

The channel stereo.

Function Documentation

◆ cyhal_pdm_pcm_init()

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
[out]objPointer to a PDM/PCM object. The caller must allocate the memory for this object but the init function will initialize its contents.
[in]pin_dataThe pin to use for PDM input
[in]pin_clkThe pin to use for PDM clock output
[in]clk_sourceThe clock source for PDM/PCM block
[in]cfgThe configuration for the PDM/PCM block
Returns
The status of the init request

◆ cyhal_pdm_pcm_free()

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
[in,out]objThe PDM/PCM object to deinitialize

◆ cyhal_pdm_pcm_start()

cy_rslt_t cyhal_pdm_pcm_start ( cyhal_pdm_pcm_t obj)

Start the PDM/PCM operation.

Parameters
[in]objThe PDM/PCM object to start
Returns
the status of the start request

◆ cyhal_pdm_pcm_stop()

cy_rslt_t cyhal_pdm_pcm_stop ( cyhal_pdm_pcm_t obj)

Stop the PDM/PCM operation.

Parameters
[in]objThe PDM/PCM object to start
Returns
the status of the stop request

◆ cyhal_pdm_pcm_is_enabled()

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
[in]objThe I2S peripheral to check
Returns
Whether the I2S receive function is enabled.

◆ cyhal_pdm_pcm_set_gain()

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
[in]objThe PDM/PCM object to configure
[in]gain_leftThe gain of the left channel in units of 0.5 dB
[in]gain_rightThe 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.

◆ cyhal_pdm_pcm_clear()

cy_rslt_t cyhal_pdm_pcm_clear ( cyhal_pdm_pcm_t obj)

Clears the hardware buffer.

Parameters
[in]objThe PDM/PCM peripheral
Returns
The status of the clear request

◆ cyhal_pdm_pcm_read()

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
[in]objThe PDM/PCM peripheral
[out]dataPointer 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.
[in,out]lengthNumber of 32-bit words to read, updated with the number actually read
Returns
The status of the read request

◆ cyhal_pdm_pcm_read_async()

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
[in]objThe PDM/PCM object
[out]dataPointer 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.
[in]lengthNumber of words to read
Returns
The status of the read_async request

◆ cyhal_pdm_pcm_is_pending()

bool cyhal_pdm_pcm_is_pending ( cyhal_pdm_pcm_t obj)

Checks if an async read operation is pending.

Parameters
[in]objThe PDM/PCM peripheral to check
Returns
Indication of whether a PDM/PCM async operation is pending

◆ cyhal_pdm_pcm_abort_async()

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
[in]objThe PDM/PCM peripheral to stop
Returns
The status of the abort_async request

◆ cyhal_pdm_pcm_register_callback()

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
[in]objThe PDM/PCM object
[in]callbackThe callback handler which will be invoked when the interrupt fires
[in]callback_argGeneric argument that will be provided to the callback when called

◆ cyhal_pdm_pcm_enable_event()

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
[in]objThe PDM/PCM object
[in]eventThe PDM/PCM event type
[in]intr_priorityThe priority for NVIC interrupt events
[in]enableTrue to turn on events, False to turn off

◆ cyhal_pdm_pcm_set_async_mode()

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
[in]objThe PDM/PCM object
[in]modeThe transfer mode
[in]dma_priorityThe 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