PdmRx.hpp

template<unsigned BLOCK_SIZE, class SubType>
class mic_array::PdmRxService

Used to collect PDM sample data from a port.

This class is used to collect blocks of PDM data from a port and send the data to a decimator for further processing.

PdmRxService is a base class using CRTP. Subclasses extend PdmRxService providing themselves as the template parameter SubType.

This base class provides the logic for aggregating PDM data taken from a port into blocks, and a subclass is required to provide methods SubType::ReadPort() and SubType::SendBlock().

SubType::ReadPort() is responsible for reading 1 word of data from p_pdm_mics.

SubType::SendBlock() is provided a block of PDM data as a pointer and is responsible for signaling that to the subsequent processing stage. (Called from PdmRx thread or ISR)

SubType::GetPdmBlock() (called from MicArray thread) is responsible for receiving a block of PDM data from SubType::SendBlock() as a pointer, deinterleaving the buffer contents, and returning a pointer to the PDM data in the format expected by the mic array unit’s decimator component.

Template Parameters
  • BLOCK_SIZE – Number of words of PDM data per block.

  • SubType – Subclass of PdmRxService

Public Functions

void SetPort(port_t p_pdm_mics)

Set the port from which to collect PDM samples.

void ProcessNext()

Perform a port read and if a new block has completed, signal.

void ThreadEntry()

Entry point for PDM processing thread.

This function loops forever, calling ProcessNext() with each iteration.

Public Static Attributes

static constexpr unsigned BlockSize = BLOCK_SIZE

Number of words of PDM data per block.

template<unsigned CHANNELS_IN, unsigned CHANNELS_OUT, unsigned SUBBLOCKS>
class mic_array::StandardPdmRxService : public mic_array::PdmRxService<CHANNELS_IN * SUBBLOCKS, StandardPdmRxService<CHANNELS_IN, CHANNELS_OUT, SUBBLOCKS>>

PDM rx service which uses a streaming channel to send a block of data by pointer.

This class can run the PDM rx service either as a stand-alone thread or through an interrupt.

A streaming channel is used to transfer control of the PDM data block between contexts (i.e. thread->thread or ISR->thread).

Inter-context Transfer

The MicArray unit receives blocks of PDM data from an instance of this class by calling GetPdmBlock(), which blocks until a new PDM block is available.

The buffer transferred by SendBlock() contains CHANNELS_IN*SUBBLOCKS words of PDM data forCHANNELS_INmicrophone channels. The words are stored in reverse order of arrival. Seedeinterleave_pdm_samples<>()` for additional details on this format.

Layouts

Within GetPdmBlock() (i.e. mic array thread) the PDM data block is deinterleaved and copied to another buffer in the format required by the decimator component, which is returned by GetPdmBlock(). This buffer contains samples for CHANNELS_OUT microphone channels.

In some cases an application may be required to capture more microphone channels than should actually be processed by subsequent processing stages (including the decimator component). For example, this may be the case if 4 microphone channels are desired but only an 8 bit wide port is physically available to capture the samples.

Channel Filtering

This class template has a parameter both for the number of channels to be captured by the port (CHANNELS_IN), as well as for the number of channels that are to be output for consumption by the MicArray’s decimator component (CHANNELS_OUT).

When the PDM microphones are in an SDR configuration, CHANNELS_IN must be the width (in bits) of the xCore port to which the microphones are physically connected. When in a DDR configuration, CHANNELS_IN must be twice the width (in bits) of the xCore port to which the microphones are physically connected.

CHANNELS_OUT is the number of microphone channels to be consumed by the decimator unit (i.e. must be the same as the MIC_COUNT template parameter of the decimator component). If all port pins are connected to microphones, this parameter will generally be the same as CHANNELS_IN.

The input channel index of a microphone depends on the pin to which it is connected. Each pin connected to a port has a bit index for that port, given in the ‘Signal Description and GPIO’ section of your package’s datasheet.

Channel Index (Re-)Mapping

Suppose an N-bit port is used to capture microphone data, and a microphone is connected to bit B of that port. In an SDR microphone configuration, the input channel index of that microphone is B &#8212; the same as the port bit index.

In a DDR configuration, that microphone will be on either input channel index B or B+N, depending on whether that microphone is configured for in-phase capture or out-of-phase capture.

Sometimes it may be desirable to re-order the microphone channel indices. This is likely the case, for example, when CHANNELS_IN > CHANNELS_OUT.

By default output channels are mapped from the input channels with the same index. If CHANNELS_IN > CHANNELS_OUT, this means that the input channels with the highest CHANNELS_IN-CHANNELS_OUT indices are dropped by default.

The MapChannel() and MapChannels() methods can be used to specify a non-default mapping from input channel indices to output channel indices. It takes a pointer to a CHANNELS_OUT-element array specifying the input channel index for each output channel.

Template Parameters
  • CHANNELS_IN – The number of microphone channels to be captured by the port.

  • CHANNELS_OUT – The number of microphone channels to be delivered by this StandardPdmRxService instance.

  • SUBBLOCKS – The number of 32-sample sub-blocks to be captured for each microphone channel.

Public Functions

uint32_t ReadPort()

Read a word of PDM data from the port.

Returns

A uint32_t containing 32 PDM samples. If MIC_COUNT >= 2 the samples from each port will be interleaved together.

void SendBlock(uint32_t block[CHANNELS_IN * SUBBLOCKS])

Send a block of PDM data to a listener.

Parameters

block – PDM data to send.

void Init(port_t p_pdm_mics)

Initialize this object with a channel and port.

Parameters

p_pdm_mics – Port to receive PDM data on.

void MapChannels(unsigned map[CHANNELS_OUT])

Set the input-output mapping for all output channels.

By default, input channel index k maps to output channel index k.

This method overrides that behavior for all channels, re-mapping each output channel such that output channel k is derived from input channel map[k].

Note

Changing the channel mapping while the mic array unit is running is not recommended.

Parameters

map – Array containing new channel map.

void MapChannel(unsigned out_channel, unsigned in_channel)

Set the input-output mapping for a single output channel.

By default, input channel index k maps to output channel index k.

This method overrides that behavior for a single output channel, configuring output channel out_channel to be derived from input channel in_channel.

Note

Changing the channel mapping while the mic array unit is running is not recommended.

Parameters
  • out_channel – Output channel index to be re-mapped.

  • in_channel – New source channel index for out_channel.

void InstallISR()

Install ISR for PDM reception on the current core.

Note

This does not unmask interrupts.

void UnmaskISR()

Unmask interrupts on the current core.

uint32_t *GetPdmBlock()

Get a block of PDM data.

Because blocks of PDM samples are delivered by pointer, the caller must either copy the samples or finish processing them before the next block of samples is ready, or the data will be clobbered.

Note

This is a blocking call.

Returns

Pointer to block of PDM data.