TI-RTOS Drivers  tidrivers_full_2_20_01_10
Data Structures | Macros | Typedefs | Enumerations | Functions | Variables
PDMCC26XX.h File Reference

Detailed Description

PDM driver implementation for a CC26XX PDM controller.

============================================================================

The PDM header file should be included in an application as follows:

Overview

This driver is written to be able to perform continuous audio streaming of PDM data from a microphone. It also controls one DIO to be able to turn on power to the microphone.

This PDM driver performs two operations that requires processing

This driver is configured to process 256 bytes of PDM data provided by the I2S hardware module at a time, sampled at 1.024 Mbps. The PDM driver consequently receives such a buffer approximately every 2ms. A frame of PDMCC26XX_Params.retBufSizeInBytes PCM data bytes minus four metadata bytes is provided to the application after being filled by all or part of one or more 64 byte buffers of PCM data derived from the 256 bytes of PDM data. The resulting PCM frame provided to the application is a 16bit PCM signal sampled at 16kHz.

The driver creates a separate task to run in.

Note
The application must allow for the PDM driver task to run often enough to process the data received from I2S driver approximately every 2ms.

The driver currently only samples on a single edge of the I2S clock.

General Behaviour

Before using PDM on CC26XX:

While using PDM on CC26XX:

After PDM operation has ended:

Error Handling

The application is notified of errors via the registered callback function.

Lost Frames

If the application fails to consume buffers in a timely manner and consequently the heap is full when driver tries to allocate a new buffer for new incoming data, the driver will drop all new incoming data until a buffer can be allocated to store it. Data is dropped one PCM data buffer at a time , even though it is streamed into the device and copied into the buffer in smaller chunks. This is done to keep the data expected in any buffer in sync with the sequence number of the buffer that keeps incrementing even when the buffer is dopped. The application may keep track of lost frames by comparing sequence numbers.

Hence, the PDM stream will never have a buffer overflow, but if the memory available in the heap is too low it may lose frames because because there is nowhere to put the incoming

If the heap frees up again and the PDM task runs, it will automatically resume normal operation again. The only application-observable difference is the incremented version number.

PDMCC26XX_open Failing

PDMCC26XX_open() returns NULL and rolls back all prior parts of the initialisation if any part of the initialisation fails. The following can cause PDMCC26XX_open() to fail:

PDMCC26XX_startStream Failing

PDMCC26XX_startStream() returns false if it fails. The following can cause PDMCC26XX_startStream() to fail:

PDMCC26XX_stopStream Failing

PDMCC26XX_stopStream() returns false if it fails. The following can cause PDMCC26XX_stopStream() to fail:

Power Management

The PDMCC26XX driver sets a power constraint while streaming to keep the device out of standby. When the stream has ended, the power constraint is released.

The following statements are valid:

Supported Functions

API function Description
PDMCC26XX_init() Initialize PDM driver
PDMCC26XX_open() Set system dependencies, configure pins
PDMCC26XX_startStream() Turn on mic, start stream and prevent standby
PDMCC26XX_stopStream() Stop stream and release standby hold, turn off mic
PDMCC26XX_requestBuffer() Request a buffer from the driver
PDMCC26XX_close() Disable HW and release system dependencies

Standard Use Case

The standard use case involves calling PDMCC26XX_open() once and calling PDMCC26XX_startStream() and PDMCC26XX_stopStream() to start and stop the stream as needed. PDMCC26XX_close() is called when the PDM driver will no longer be needed again. In order for the PDM driver task to run, the application pends on a semaphore that is posted in the PDMCC26XX_Params::callbackFxn. In this example, the application requests 128 buffers. In a real application, the process of pending on a semaphore, requesting a buffer, and freeing it would be repeated as often as required by the use case before stopping the stream.

void bufRdy_callback(PDMCC26XX_Handle handle, PDMCC26XX_StreamNotification *pStreamNotification)
{
PDMCC26XX_Status streamStatus = pStreamNotification->status;
Semaphore_post(Semaphore_handle(&bufferReadySemaphore));
}
else {
// Handle the error
}
}
static void applicationTask(UArg a0, UArg a1){
Semaphore_Params semParams;
PDMCC26XX_BufferRequest bufferRequest;
const uint16_t returnBufferSize = 64;
const uint8_t numberOfPcmBuffersToRequest = 128;
// Initialize semaphore
Semaphore_Params_init(&semParams);
semParams.mode = Semaphore_Mode_BINARY;
Semaphore_construct(&bufferReadySemaphore, 0, &semParams);
// Set up parameters for PDM streaming with compression
PDMCC26XX_Params pdmParams = {
.callbackFxn = bufRdy_callback,
.useDefaultFilter = true,
.decimationFilter = NULL,
.micGain = PDMCC26XX_GAIN_12,
.micPowerActiveHigh = true,
.applyCompression = true,
.startupDelayWithClockInSamples = 0,
.retBufSizeInBytes = returnBufferSize,
.mallocFxn = &malloc,
.freeFxn = &free,
.custom = NULL
};
// Try to open the PDM driver
if(pdmHandle = PDMCC26XX_open(&pdmParams) == NULL){
// Handle PDMCC26XX_open() failing
}
// Try to start streaming
if(PDMCC26XX_startStream(pdmHandle)){
uint8_t pcmBuffersRequestedSoFar;
// Request numberOfPcmBuffersToRequest buffers and then stop the stream
for (pcmBuffersRequestedSoFar = 0; pcmBuffersRequestedSoFar < numberOfPcmBuffersToRequest; pcmBuffersRequestedSoFar++){
// Pend on the semaphore until a buffer is available from the PDM driver
Semaphore_pend(Semaphore_handle(&bufferReadySemaphore), BIOS_WAIT_FOREVER);
// Now request a buffer as it was indicated that one is available
PDMCC26XX_requestBuffer(pdmHandle, &bufferRequest);
// Process bufferRequest
// Free the buffer
my_free(bufferRequest.buffer, returnBufferSize);
}
// Try to stop the stream
if(!PDMCC26XX_stopStream(pdmHandle)){
// Handle PDMCC26XX_stopStream() failing
}
}
else{
// Handle PDMCC26XX_startStream() failing
}
}

Instrumentation

The PDM driver interface produces log statements if instrumentation is enabled.

Instrumentation Description
Diags_USER1 Logs the start and end of each API call of the PDM driver and progress through events
Diags_USER2 Logs occurances in the I2S sub-module of the PDM driver
Warnings Logs unexpected events such as initialisations or memory allocations failing

#include <ti/sysbios/knl/Semaphore.h>
#include <ti/drivers/PIN.h>
#include <ti/sysbios/family/arm/m3/Hwi.h>
#include <ti/drivers/Power.h>
#include <ti/drivers/power/PowerCC26XX.h>
Include dependency graph for PDMCC26XX.h:

Go to the source code of this file.

Data Structures

struct  PDMCC26XX_metaData
 Metadata associated with an array of PCM data. More...
 
struct  PDMCC26XX_pcmBuffer
 PCM buffer pointed to in a PDMCC26XX_BufferRequest. More...
 
struct  PDMCC26XX_Config
 The PDMCC26XX_Config structure contains a set of pointers used to characterize the PDMCC26XX driver implementation. More...
 
struct  PDMCC26XX_HWAttrs
 PDMCC26XX Hardware attributes. More...
 
struct  PDMCC26XX_StreamNotification
 A PDMCC26XX_StreamNotification data structure is used with PDMCC26XX_CallbackFxn(). Provides notification about available buffers and potential errors. More...
 
struct  PDMCC26XX_BufferRequest
 A PDMCC26XX_BufferRequest data structure is used with PDMCC26XX_requestBuffer(). More...
 
struct  PDMCC26XX_Params
 PDMCC26XX Parameters are used to with the PDMCC26XX_open() call. Default values for these parameters are set using PDMCC26XX_Params_init(). More...
 
struct  PDMCC26XX_Object
 PDMCC26XX Object. More...
 

Macros

#define ti_sysbios_family_arm_m3_Hwi__nolocalnames
 
#define PDM_TASK_STACK_SIZE   500
 
#define PDM_NUM_OF_CHANNELS   2
 
#define PDM_BLOCK_SIZE_IN_SAMPLES   64
 
#define PDM_BUFFER_SIZE_IN_BLOCKS   3
 
#define PCM_COMPRESSION_RATE   4
 
#define PCM_METADATA_SIZE   4
 
#define PDM_SAMPLE_SIZE   16
 
#define PCM_SAMPLE_SIZE   16
 
#define PDM_NUMBER_OF_PINS   1
 
#define PDM_EVT_BLK_RDY   Event_Id_00
 
#define PDM_EVT_START   Event_Id_01
 
#define PDM_EVT_BLK_ERROR   Event_Id_02
 
#define PDM_EVT_CLOSE   Event_Id_03
 
#define PDM_DECIMATION_STARTUP_DELAY_IN_SAMPLES   32
 
#define PDM_ROLLBACK_OPEN   1 << 0
 
#define PDM_ROLLBACK_ACTIVE_PCM_BUFFER   1 << 1
 
#define PDM_ROLLBACK_I2S_DRIVER   1 << 2
 
#define PDM_ROLLBACK_PIN   1 << 3
 
#define PDMCC26XX_COMPR_ITER_OUTPUT_SIZE   16
 
#define PDMCC26XX_CPY_ITER_OUTPUT_SIZE   64
 

Typedefs

typedef uint16_t pdmSample_t
 
typedef int16_t pcmSample_t
 
typedef void *(* PDMCC26XX_MallocFxn) (size_t memSize)
 PDMCC26XX_MallocFxn is a function pointer for the malloc function to be used by the driver. More...
 
typedef void(* PDMCC26XX_FreeFxn) (void *ptr, size_t memSize)
 PDMCC26XX_FreeFxn is a function pointer for the free function to be used by the driver. This is needed for memory clean up, if something goes wrong. More...
 
typedef struct PDMCC26XX_Config PDMCC26XX_Config
 The PDMCC26XX_Config structure contains a set of pointers used to characterize the PDMCC26XX driver implementation. More...
 
typedef struct PDMCC26XX_HWAttrs PDMCC26XX_HWAttrs
 PDMCC26XX Hardware attributes. More...
 
typedef struct PDMCC26XX_ConfigPDMCC26XX_Handle
 A handle that is returned from a PDMCC26XX_open() call. More...
 
typedef enum PDMCC26XX_Status PDMCC26XX_Status
 Status codes that are set by the PDM driver. More...
 
typedef enum PDMCC26XX_Gain PDMCC26XX_Gain
 Predefined gain settings. More...
 
typedef struct PDMCC26XX_StreamNotification PDMCC26XX_StreamNotification
 A PDMCC26XX_StreamNotification data structure is used with PDMCC26XX_CallbackFxn(). Provides notification about available buffers and potential errors. More...
 
typedef void(* PDMCC26XX_CallbackFxn) (PDMCC26XX_Handle handle, PDMCC26XX_StreamNotification *streamNotification)
 The definition of a callback function used when buffers are ready. More...
 
typedef struct PDMCC26XX_BufferRequest PDMCC26XX_BufferRequest
 A PDMCC26XX_BufferRequest data structure is used with PDMCC26XX_requestBuffer(). More...
 
typedef struct PDMCC26XX_Params PDMCC26XX_Params
 PDMCC26XX Parameters are used to with the PDMCC26XX_open() call. Default values for these parameters are set using PDMCC26XX_Params_init(). More...
 
typedef struct PDMCC26XX_Object PDMCC26XX_Object
 PDMCC26XX Object. More...
 

Enumerations

enum  PDMCC26XX_Status {
  PDMCC26XX_STREAM_IDLE,
  PDMCC26XX_STREAM_BLOCK_READY,
  PDMCC26XX_STREAM_BLOCK_READY_BUT_PDM_OVERFLOW,
  PDMCC26XX_STREAM_ERROR,
  PDMCC26XX_STREAM_STOPPING,
  PDMCC26XX_STREAM_STOPPED,
  PDMCC26XX_STREAM_FAILED_TO_STOP
}
 Status codes that are set by the PDM driver. More...
 
enum  PDMCC26XX_Gain {
  PDMCC26XX_GAIN_24,
  PDMCC26XX_GAIN_18,
  PDMCC26XX_GAIN_12,
  PDMCC26XX_GAIN_6,
  PDMCC26XX_GAIN_0,
  PDMCC26XX_GAIN_END
}
 Predefined gain settings. More...
 

Functions

void PDMCC26XX_init (PDMCC26XX_Handle handle)
 PDM CC26XX initialization. More...
 
PDMCC26XX_Handle PDMCC26XX_open (PDMCC26XX_Params *params)
 Function to initialize the CC26XX PDM peripheral specified by the particular handle. The parameter specifies which mode the PDM will operate. More...
 
void PDMCC26XX_close (PDMCC26XX_Handle handle)
 Function to close a given CC26XX PDM peripheral specified by the PDM handle. More...
 
bool PDMCC26XX_startStream (PDMCC26XX_Handle handle)
 Function to start streaming PDM data. More...
 
bool PDMCC26XX_stopStream (PDMCC26XX_Handle handle)
 Function to stop streaming PDM data. More...
 
bool PDMCC26XX_requestBuffer (PDMCC26XX_Handle handle, PDMCC26XX_BufferRequest *bufferRequest)
 Function for requesting buffer. More...
 

Variables

const PDMCC26XX_Config PDMCC26XX_config []
 

Macro Definition Documentation

#define ti_sysbios_family_arm_m3_Hwi__nolocalnames

The following allows this header file to be included in an application file which also includes ti/sysbios/hal/Hwi.h.

#define PDM_TASK_STACK_SIZE   500

Defines TI-RTOS stack size allocation.

#define PDM_NUM_OF_CHANNELS   2

Use both word clock phases to get continuous PDM stream

Note
Internal use only
#define PDM_BLOCK_SIZE_IN_SAMPLES   64

PDM block size in number of 16bit samples. Each PDM sample actually consume 32 bits, given that we assume 16kHz sampling rate. Hence, the number of PDM samples are always twice the potential number of 16bit PCM samples.

Note
Internal use only
#define PDM_BUFFER_SIZE_IN_BLOCKS   3

PDM buffer size in number of blocks. We assume that we will be able to consume PDM samples in a timely manner. This allows us to use the minium number of blocks (3) for the PDMCC26XX driver.

#define PCM_COMPRESSION_RATE   4

Compression rate if compression is enabled

Note
Internal use only
#define PCM_METADATA_SIZE   4

PCM data metadata size. When a buffer is requested there will be metadata prepended. In other words the pointer returned points to the metadata header. Depending on the mode, this contains differen information. The first byte is always an 8-bit sequence number.

Note
Internal use only
#define PDM_SAMPLE_SIZE   16

PDM sample size. Although there are 32 bits per sample at 16kHz we need to set it to 16 as part of the PDMCC26XX module configuration.

Note
Internal use only
#define PCM_SAMPLE_SIZE   16

PCM sample size in bits

Note
Internal use only since only 16 bits are supported
#define PDM_NUMBER_OF_PINS   1

Number of GPIOs used. When in debug mode 4 pins are used in addition to the pin to control power to the microphone.

Note
Internal use only
#define PDM_EVT_BLK_RDY   Event_Id_00

PDM event set in the callback from the PDMCC26XX driver every time a block is ready for PDM2PCM conversion.

Note
Internal use only
#define PDM_EVT_START   Event_Id_01

PDM event set to kick off stream from PDM thread context.

Note
Internal use only
#define PDM_EVT_BLK_ERROR   Event_Id_02

PDM event set in the callback from the PDMCC26XX driver in case an error occurs.

Note
Internal use only
#define PDM_EVT_CLOSE   Event_Id_03

PDM event set in the callback from the PDMCC26XX driver when the application calls PDMCC26XX_close().

Note
Internal use only
#define PDM_DECIMATION_STARTUP_DELAY_IN_SAMPLES   32

This value defines how many samples are discarded at minimum each time the PDM stream starts. The first few samples that are processed by the driver will not be representative of their actual value as the decimation filter has not sufficiently updated its internal state. A value < 8 is not reccomended, as the distortion of the signal is greatest there.

Note
Internal use only
#define PDM_ROLLBACK_OPEN   1 << 0

Reverses the driver being set to open in the object

Note
Internal use only
#define PDM_ROLLBACK_ACTIVE_PCM_BUFFER   1 << 1

Reverses the allocation of the activePcmBuffer

Note
Internal use only
#define PDM_ROLLBACK_I2S_DRIVER   1 << 2

Reverses the opening of the I2S driver

Note
Internal use only
#define PDM_ROLLBACK_PIN   1 << 3

Reverses the allocation of the PDM pin in the PIN driver

Note
Internal use only
#define PDMCC26XX_COMPR_ITER_OUTPUT_SIZE   16

Number of compressed bytes produced by each PDM->PCM conversion and compression

Note
Internal use only
#define PDMCC26XX_CPY_ITER_OUTPUT_SIZE   64

Number of uncompressed bytes produced by eahc PDM->PCM conversion and memcpy

Note
Internal use only

Typedef Documentation

typedef uint16_t pdmSample_t

PDM sample type. Prepared for future support of 24 sample size.

Note
Internal use only
typedef int16_t pcmSample_t

PCM sample type.

Note
Internal use only
typedef void*(* PDMCC26XX_MallocFxn) (size_t memSize)

PDMCC26XX_MallocFxn is a function pointer for the malloc function to be used by the driver.

typedef void(* PDMCC26XX_FreeFxn) (void *ptr, size_t memSize)

PDMCC26XX_FreeFxn is a function pointer for the free function to be used by the driver. This is needed for memory clean up, if something goes wrong.

The PDMCC26XX_Config structure contains a set of pointers used to characterize the PDMCC26XX driver implementation.

PDMCC26XX Hardware attributes.

These fields are used by the PDM driver

A handle that is returned from a PDMCC26XX_open() call.

Status codes that are set by the PDM driver.

Predefined gain settings.

Gain is controlled by modifying the first coefficient of the PDM filter. Use these defines to get correct gain setting. All these values are in dB. Default filter will add 12dB gain. In fact this is not an amplification, this setting uses all the information in the PDM samples, so if use case allows it this will have the least compromised range. PDM2PCM algotrithm returns false if any of the samples decimated goes above 2^16 - 1, i.e. the sample clipped during decimation. This information can be used for automatic gain control.

A PDMCC26XX_StreamNotification data structure is used with PDMCC26XX_CallbackFxn(). Provides notification about available buffers and potential errors.

typedef void(* PDMCC26XX_CallbackFxn) (PDMCC26XX_Handle handle, PDMCC26XX_StreamNotification *streamNotification)

The definition of a callback function used when buffers are ready.

Parameters
PDMCC26XX_HandlePDMCC26XX_Handle

A PDMCC26XX_BufferRequest data structure is used with PDMCC26XX_requestBuffer().

buffer is a pointer to the requested buffer. It is NULL if no buffer is available. Each buffer contains a metadata header of size PCM_METADATA_SIZE. The first byte of the metadata is always an 8 bit sequence number. The other bytes depends on mode.

Mode Interpretation of bufferIn being NULL after returning
Blocking mode Request timed out and still no buffer available
Non-Blocking mode No buffer available

PDMCC26XX Parameters are used to with the PDMCC26XX_open() call. Default values for these parameters are set using PDMCC26XX_Params_init().

See also
PDMCC26XX_Params_init

PDMCC26XX Object.

The application must not access any member variables of this structure!

Enumeration Type Documentation

Status codes that are set by the PDM driver.

Enumerator
PDMCC26XX_STREAM_IDLE 

Idle mode. Stream not started

PDMCC26XX_STREAM_BLOCK_READY 

Buffer ready

PDMCC26XX_STREAM_BLOCK_READY_BUT_PDM_OVERFLOW 

Buffer ready, but the PDMCC26XX driver is impending failure if not serviced in time. Stream is likely to stop now.

PDMCC26XX_STREAM_ERROR 

Driver error

PDMCC26XX_STREAM_STOPPING 

A stop was requested and this is the last buffer to be produced.

PDMCC26XX_STREAM_STOPPED 

Unused

PDMCC26XX_STREAM_FAILED_TO_STOP 

Buffer ready

Predefined gain settings.

Gain is controlled by modifying the first coefficient of the PDM filter. Use these defines to get correct gain setting. All these values are in dB. Default filter will add 12dB gain. In fact this is not an amplification, this setting uses all the information in the PDM samples, so if use case allows it this will have the least compromised range. PDM2PCM algotrithm returns false if any of the samples decimated goes above 2^16 - 1, i.e. the sample clipped during decimation. This information can be used for automatic gain control.

Enumerator
PDMCC26XX_GAIN_24 

24dB gain

PDMCC26XX_GAIN_18 

18dB gain

PDMCC26XX_GAIN_12 

12dB gain. Default

PDMCC26XX_GAIN_6 

6dB gain

PDMCC26XX_GAIN_0 

0dB gain

PDMCC26XX_GAIN_END 

Internal use only

Function Documentation

void PDMCC26XX_init ( PDMCC26XX_Handle  handle)

PDM CC26XX initialization.

PDMCC26XX_Handle PDMCC26XX_open ( PDMCC26XX_Params params)

Function to initialize the CC26XX PDM peripheral specified by the particular handle. The parameter specifies which mode the PDM will operate.

The function will set a dependency on the PDM module, which in turn powers up the module and enables the clock. IOs are also allocated, however the PDM driver will not begin streaming audio until PDMCC26XX_startStream() is called.

Precondition
PDM controller has been initialized
Parameters
paramsPointer to a parameter block. Will use default parameters if NULL
Returns
A PDMCC26XX_Handle on success or a NULL on an error or if it has been already opened
See also
PDMCC26XX_close()
void PDMCC26XX_close ( PDMCC26XX_Handle  handle)

Function to close a given CC26XX PDM peripheral specified by the PDM handle.

Posts an event that shuts down the I2S hardware, frees all memory used by the driver on the heap, releases the pins back to the PIN driver, and releases the dependency on the corresponding power domain.

Precondition
PDMCC26XX_open() has to be called first.
Postcondition
The PDM task must be allowed to run to synchronously shut down the driver
Parameters
handleA PDMCC26XX_Handle returned from PDMCC26XX_open()
See also
PDMCC26XX_open
bool PDMCC26XX_startStream ( PDMCC26XX_Handle  handle)

Function to start streaming PDM data.

Posts an event that tells the I2S hardware to start streaming and the PDM task to start processing incoming data.

Precondition
PDMCC26XX_open() has to be called first.
Postcondition
The PDM task must be allowed to run (by e.g. pending on a semaphore in the application task) to process incoming PDM data from the I2S module.
Parameters
handleA PDM handle returned from PDMCC26XX_open()
Returns
true if transfer is successful and false if not
See also
PDMCC26XX_open(), PDMCC26XX_stopStream()
bool PDMCC26XX_stopStream ( PDMCC26XX_Handle  handle)

Function to stop streaming PDM data.

Blocks while the I2S module shuts down gracefully. Subsequently posts an event to let the PDM task process any remaining data.

Precondition
PDMCC26XX_startStream() has to be called first.
Parameters
handleA PDM handle returned from PDMCC26XX_open()
Returns
True if stream stopped successfully and false if not
Postcondition
Process all available PCM buffers by calling PDMCC26XX_requestBuffer() until it returns false. Otherwise, the available PCM buffers will take up space on the heap until PDMCC26XX_close() or PDMCC26XX_startStream() are called.
See also
PDMCC26XX_open(), PDMCC26XX_startStream()
bool PDMCC26XX_requestBuffer ( PDMCC26XX_Handle  handle,
PDMCC26XX_BufferRequest bufferRequest 
)

Function for requesting buffer.

PDMCC26XX_requestBuffer returns immediately even if no buffer is available. The caller is notified through events each time a buffer is available. However, more than one buffer may be available. Hence, the caller should request even without notification if the caller is ready to process.

Precondition
PDMCC26XX_open() and PDMCC26XX_startStream() has to be called first.
Parameters
handleA PDM handle returned from PDMCC26XX_open()
*bufferRequestPointer to PDMCC26XX_BufferRequest struct
Returns
True if request is successful and false if not
See also
PDMCC26XX_open(), PDMCC26XX_startStream()

Variable Documentation

const PDMCC26XX_Config PDMCC26XX_config[]

PDMCC26XX_Config struct defined in the board file

Copyright 2016, Texas Instruments Incorporated