Note |
---|
Notice: Pre-Release Documentation |
Release 4.1 is adding
Can be on different Hexagon DSPs
Can be on different clockDividers
Can utilize different block sizes and sample rates
TDM initialization follows a prescribed sequence including initializing bitclk first followed by the frame sync.
Synchronous TDM ports time align themselves automatically to within 1 sample.
Asynchronous serial ports including an ASRC and output data at a fixed sample rate and block size.
Synchronization Modes
The serial port modules support synchronous and asynchronous operation. In synchronous operation, the serial ports are all clocked off the same master clock. In asynchronous operation, the serial port has a different clock that is not equal to the master clock. Operation can be further classified as
Synchronous Master - Operates at the smallest block size and generates the primary interrupt. This port must be on the Primary Audio Core (PAC) which is specified in the system configuration file. Only one serial port in the system can be defined as the Synchronous Master.
Synchronous Aligned – the serial ports start simultaneously and remain in lock step throughout. This requires external hardware connections to share serial port clocks and framesyncs. On the SA8255, this is achieved by tying the serial ports to the master clock, starting DMA, and then starting the frame sync.
This is achieved on SA8797 by configuring the serial ports to use the master clock together with the Group Bonding mechanism to start all DMA simultaneously. All synchronous serial ports must be on the same audio processor (TDM bonding only works on a single core.
Synchronous Aligned serial ports are able to achieve the lowest possible input to output latency (equal to 2 times the block size). This is the ideal solution for low latency applications like RNC.
Synchronous Unaligned – the serial ports are driven off the master clock but do not start synchronously. The data stream is driven by the same clock source/root as the master clock, but is misaligned in time. The vast majority of custom designs will use this approach, and the Audio Weaver TDM modules are able to time align these ports to within 1 sample of the Synchronous Master.
Asynchronous – the serial port uses its own clock source / domain. It has a double buffer and hooks its own DMA completion interrupt. In its interrupt handler, audio data is copied from the DMA double buffer to the input buffer of an Asynchronous Sample Rate Converter. Then in the module’s processing function, sample rate conversion occurs and data is copied from (to) the temporary buffer to the Audio Weaver wire buffer.
We will refer to these different synchronization schemes throughout this document and will use the abbreviations SM, SA, SU, and AS for Synchronous Master, Synchronous Aligned, Synchronous Unaligned, and Asynchronous operation.
There will be two different Audio Weaver modules for interfacing to the TDM ports, The SnapdragonSyncTDMPort will handle all of the synchronous use cases and will support input and output ports. The SnapdragonAsyncTDMPort will handle the asynchronous use cases.
The serial ports on the Snapdragon record a 64-bit time stamp upon buffer completion (the ping/pong switch). This time stamp has a resolution of 19.2 MHz and is written by the hardware peripherals. It is very accurate and does not rely on a software interrupt which may have jitter. This time stamp information will be used to align unaligned transfers and for the ASRC control loop needed for AS ports.
There are separate synchronous and asynchronous port interface modules as shown below. Each module can be used for input or output.
...
We describe the Synchronous and Asynchronous ports separately.
Hexagon TDM Port - Synchronous [R4.1]
This module supports all of the Synchronous clocking schemes described above.
Module Arguments [R4.1]
direction - specifies whether this is a sink device (=0) or a source device (=1):
...
When configured as a TDM_SOURCE, the module has an audio output port (on the right), and a Timing Information port (TI) located on the top:
...
When configured as a TDM_SINK, the module has an input port on the left side and a Timing Information port (TI) located on the top:
...
numChannels, blockSize, and sampleRate - specify the properties of the TDM port. If this is an input module, then these values will also specify the properties of the output wire. If this is an output port, then the wire properties at the input must match these values. The sampleRate value is taken from a droplist:
...
clockingMode - specifies the clocking properties that was described above:
...
dataFormat - taken from AudioLite. You should only use “DATAFORMAT_FIXED_POINT”.
...
All other properties are taken directly from the AudioLite APIs and are used when opening the port.
...
Timing Information Output Pin
This pin has a size of 6x1 samples and contains integer data. (This is a control signal with 6 channels and a block size of 1). It has a sample rate of sampleRate/blockSize. It contains these values:
isStarted - Boolean value indicating whether the device has been enabled
timeStampL - the low 32-bits of the time stamp when the ping/pong buffer of the module last flipped.
timeOffsetFromMaster - time skew between this port and the SM. In microseconds. This is measured based on the DMA time stamps.
rwOffset - computed offset used to index early or late in the DMA buffer
sampleLatencyFromMaster - the final latency in samples relative to the SM port.
Module Inspector [R4.1]
...
Start - User Parameter. Allows you to turn the port on or off.
DMA Safety Delay - User Parameter. Additional use specified time delay that will be used in the offset calculation. This will be used for testing and for situations when we want to give more time for the DMA to complete. The actual math used is:
DMA Offset = floor((TS_SM - TS_SU + dmaSafeDelay) / (Sample Period))
Startup Settling Count - User Parameter. This specifies how many blocks pump cycles the module will do and continue to output zero data. This gives the module time to calculate its read/write offset so that it doesn’t introduce a pop or click when it changes.
Startup Latency - User Parameter. The BSP will wait the specified number of microseconds before enabling the serial port clocks. This value is used for testing and will allow us to play with the alignment between ports. During normal usage, it should be set to 0.
Error Status - Read Back State. Reports errors in startup or operation. 0 indicates no error.
Pump Counter - Read Back State. Increments every time the module’s processing function is called.
Time Offset to Master - Read Back State. This is the computed time skew between this port and the SM This is a floating-point number and represents microseconds.
DMA Ptr RW Offset - Read Back State. This is the computed sample offset when accessing the DMA buffer. This is calculated per block. Instead of accessing the buffer at the expected start of the ping or pong buffer, this offset is added.
Offset to Master - Read Back State. This is the true offset in samples relative to the SM device. It is used to add compensating delay in the system. If a SU device has a latency of +1 samples, then the SM should be delayed by 1 sample.
Time Alignment Between Synchronous Devices [R4.1]
The SM and all SA devices operate off the same clocks and will be completely synchronized; 0 sample latency.
When operating as a SU port, there is internal logic which uses the time stamp of each port’s DMA interrupt to align the data with the SM port. If you have dmaSafetyDelay set to 0 then the SU port will be aligned to within 1 sample for input and output ports. This could be a fractional sample delay since the clocks start independently.
If dmaSafetyDelay is nonzero, then this will add additional latency. dmaSafetyDelay is specified in microseconds and you end up with different latency from boot-to-boot. Fortunately, the timing output pin reports the actual latency (in samples) in sampleLatencyFromMaster and you can use this to time align signals in your layout. For example, if the SU port reports a sampleLatencyFromMaster of 1 sample, then it means that the SU port is 1 sample delayed relative to the SM. To align the ports, you need to add 1 sample of delay to the output of the SM port.
Hexagon TDM Port - Asynchronous [R4.1]
The Asynchronous input port operates as shown in the figure below. There is a device side, which interfaces to the serial port hardware and manages the DMA, and an Audio Weaver side which operates within the context of the Audio Weaver pump function.
...
Module arguments specify the number of channels and the output block size and sample rate in Audio Weaver. These can be changed at design time only. The device uses the same number of channels, but has separate parameters (run-time changeable) for the device block size and device sample rate. This allows you, for example, to initially operate the device at 32 kHz with a block size of 256 samples, while the audio received by Audio Weaver is 48 kHz with a block size of 48 samples. At run-time, you can change the device to 16 kHz with a block size of 128 samples, while the audio received by Audio Weaver continues to be 48 kHz with a block size of 48 samples.
Asynchronous Sample Rate Converter (ASRC) Algorithm
The first release of this module is based on DSP Concepts’ ASRC library. We expect future versions of this module to leverage a different ASRC algorithm from Qualcomm. This section briefly describes DSP Concepts’ library and it aids in understanding the overall implementation.
A conceptual view of the library and how it interfaces between the DMA buffers and Audio Weaver wire buffer is shown below.
...
This library has an input FIFO called the “jitter buffer” which stores samples at the input rate. The jitter buffer provides margin allowing the algorithm to adapt to changing sample rates. The jitter buffer is filled by calls to the function dspc_asrc_write(), and this occurs in the DMA interrupt for the serial port. The call dspc_asrc_write() executes quickly and copies a complete deviceBlockSize of data into the jitter buffer.
Then in the module’s processing function, which executes at Audio Weaver’s pump rate, the library calls the dspc_asrc_read() function. This performs fractional sample interpolation and writes the output Q31 data into the module’s output wire buffer. Every time the module pumps, it outputs one (Audio Weaver) block of data. The bulk of the processing occurs in this function and will be included when the module is profiled.
Input and output data is in Q31 format. A temporary buffer is used for format conversion prior to the call to dspc_asrc_write(). The ASRC library is designed to be thread safe with the dspc_asrc_write() and dspc_asrc_read() functions being called from different threads and even executing at the same time.
The implementation also contains a control loop for computing the input and output sample rates. This calculation uses the time stamps of the DMA buffers to adjust the fractional interpolation process.
The architecture for output devices is slightly more complicated and requires an additional FIFO in the output path as shown below.
Several things happen in the module’s processing function. First, it writes one (Audio Weaver) block of data into the jitter buffer using the call dspc_asrc_write(). The input data is at Audio Weaver’s sample rate. Next, it converts all data in the jitter buffer to output samples. This Q31 data is written into the temp buffer. Then it is format converted to the bitwidth of the TDM port and written into an output FIFO. All this processing happens in the Audio Weaver pump function. Then, in the TDM port’s interrupt handler, data is read from the FIFO and written into the DMA buffer. With this approach, everything that occurs in the Audio Weaver pump function is captured in profiling.
Module Arguments [R4.1]
The Asynchronous TDM port adds 2 more arguments as shown below.
...
maxDeviceBlockSize - specifies the maximum block size that the device will ever be configured for. This is used to size internal buffers.
asrcQuality - a droplist which configures the quality of the asynchronous sample rate converter. The choices are shown below and “Music” is the default.
The quality metric maps approximately to the distortion level in the converted signal. The distortion will be at least this many dB below the signal level:
Voice - 80 dB
Music - 100 dB
HiFi - 120 dB
This feature has not yet been implemented. In R4.1, all ASRCs are at the “Voice” performance level.
Module Inspector for Input Devices [R4.1]
The inspector for the Asynchronous TDM port when configured as an input is shown below.
...
Start - User settable parameter. Enables DMA and starts streaming audio data.
Set Device Block Size - user settable parameter. Specifies the deviceBlockSize and allows you to configure the DMA buffer size and interrupt rate of the device.
Set Device Sample Rate - User settable parameter. Specifies the sample rate of the device.
Port ISR Count - Read back state. Increments every time the device generates an interrupt at the ping / pong buffer DMA switch. This will update deviceSampleRate/deviceBlockSize times per second.
Pump Counter - Read back state. Increments every time that the module pumps in Audio Weaver. This will update sampleRate/blockSize times per second (these are the settings on the “Audio Weaver side”.)
Error Status - Read back state. Indicates if everything is functioning correctly. 0 indicates no error. See the table below.
Reset Counters - User settable parameters. Clicking “reset” will clear all counters and error status on the inspector.
ASRC Prefill Level - User settable parameter. Number of samples at the deviceSampleRate that will be filled in the ASRC’s internal “jitter buffer” before conversion starts. This helps to prevent ASRC underruns. We recommend setting this to 2 x deviceBlockSize.
ASRC Input Avail - Read back state. Free space in the ASRC’s jitter buffer. This is how many device samples can be written into the buffer before an ASRC Overrun occurs.
ASRC Output Avail - Read back state. Number of samples at Audio Weaver’s sample rate that can be pulled from the ASRC. If this goes to zero, then an ASRC Underrun occurs.
ASRC Overruns - Read back state. Counts the number of times that the DMA completes and there is insufficient room in the ASRC jitter buffer to receive the data.
ASRC Underruns - Read back state. Counts the number of times that Audio Weaver pumps and wants to pull data out of the ASRC, but there is insufficient data in the jitter buffer.
Module Inspector for Output Devices [R4.1]
The inspector for the Asynchronous output device adds another row of controls for configuring and monitoring the FIFO.
...
FIFO Prefill Level - User settable parameter. Specifies the number of samples that must be in the FIFO before data is streamed via DMA. This prevents FIFO underruns from occurring.
FIFO Input Avail - Read back variable. Number of samples that can be written by the module’s pump function into the FIFO. If this goes to zero, then a FIFO Overruns occurs.
FIFO Output Avail - Read back variable. Number of samples that can be read by the DMA handler. If this goes to zero, then a FIFO Underrun occurs.
FIFO Overruns - Read back variable. Number of times that the FIFO has overrun. This indicates that Audio Weaver wants to write ASRC output data, but the FIFO is full.
FIFO Underruns - Read back variable. Number of times that the DMA interrupt handler wants to read data from the FIFO, but there is insufficient data.
Table of Error Codes for AsyncTDMPort
Error Code | Meaning |
-1000 | Config or start-time. Failed to open the TDM port with the given configuration settings. |
-1001 | Config or start-time. Failed to set the DMA callback (should never happen). |
-1002 | Config or start-time. Failed to get the system wide time stamp resolution (should never happen) |
-1003 | Config or start-time. Failed to get configuration of the Synchronous Master serial port. This can occur if a Synchronous Master port was not defined. |
-1004 | Config or start-time. Failed to start real-time audio on the port. |
-1005 | Config or start-time. Failed to get details of the port’s DMA buffer (should never happen). |
-1006 | Real-time. Unable to fetch the port’s ping-pong buffer details including time stamp and ISR counter (should never happen). |
-2001 | Real-time. Unable to fetch the Synchronous Master port’s ping-pong buffer details including time stamp and ISR counter (should never happen). |
-2003 | Real-time. Error reading data from the ASRC algorithm (should never happen). |
-2005 | Real-time. Failure writing data into the output FIFO (should never happen). |
Run-time Reconfiguration of Asynchronous TDM Ports
The asynchronous ports allow the device properties to be changed at run-time. Use the following sequence of operations to reconfigure the port:
Disable the device.
On the inspector, uncheck “Start”.
Alternatively, via the HLOS control interface, set the variable “isStarted” to zero. This halts DMA and frees DMA memory.
Reconfigure the device.
On the inspector, set the “Device Block Size” or the “Device Sample Rate”.
Alternatively, via the HLOS control interface, set “deviceSampleRate” and “deviceBlockSize”.
Enable the device
On the inspector, check “Start”.
Alternatively, via the HLOS control interface, set the variable “isStarted” to one.
This allocates DMA memory (based on deviceSampleRate) and opens the TDM using deviceSampleRate. DMA then resumes.
Audio Startup Sequence [R4.1]
When a system is built using Audio Weaver Designer, or when an AWB file is loaded, the TDM modules are individually constructed based on their location in the signal flow. The TDM ports, however, are not started until the “audio_start” command is received. (This is usually the last command when building or loading a system.)
The Snapdragon BSP starts SM and SA TDM ports using the following sequence:
Enable the bit clock for the SM port
Enable DMA for the SA ports. This enables the DMA but does not start interrupts.
Enable SM port framesync. At this point, the SM and SA ports will be operational and generating interrupts synchronously.
After the SM and SA ports are running, then the SU and AS ports are started. There are no special startup requirements for the SU and AS ports.
On the SA8255, the TDM ports can be placed on different Hexagon cores. Each DSP boots in order and the serial ports on each core follow the sequence shown above. On the SA8255, all SM and SA ports must be on the PAC; you cannot place them on different DSPs.
During early audio, the TDM ports are started as follows:
The Primary Audio Core (PAC) initializes and loads its AWB first.
All TDM ports on the PAC are initialized using the sequence above.
Audio start command starts DMA on the PAC. Audio is active.
PAC signals GPDSP0 to start initializing
GPDSP0 loads its own AWB
GPDSP0 initializes the TDM modules in its AWB
TDM audio interrupts start on GPDSP0
GPDSP0 signals the PAC that it is done initializing
The PAC signals GPDSP0 to pump audio
PAC signals GPDSP1 to start initializing
GPDSP1 loads its own AWB
GPDSP1 initializes the TDM modules in its AWB
Audio interrupts start on GPDSP1
GPDSP1 signals the PAC that it is done initializing
The PAC signals GPDSP1 to pump audio
Early audio is fully initialized
TDM Port Latency
The input to output latency on the SA8255 ADP was measured using a loopback test. The signal path was:
TDM Output → A2B → DAC → ADC → A2B → TDM Input
The measurement included the digital buffering latency of Audio Weaver and also the latency through the analog codec. With a 0.25 msec block size (12 samples at 48 kHz), we measured a total delay of 1.6 msec. This corresponded to a 0.5 msec Audio Weaver processing delay, and a 1.1 msec analog delay. More details can be found here.
Usage Guidelines
Do not make the block sizes of your TDM ports too large. There is a limited amount of DMA memory on the Snapdragon and you may exceed this. (Audio Weaver testing has been with block sizes up to 5.0 msec.)
You are only allowed to define a single TDM port as being the Synchronous Master. If you define multiple ports as Synchronous Master, then you will get a build error.
You are allowed to place the TDM Port modules into different threads. For example, one port operates at a block size of 1 msec and is placed in thread 1A. A second port operates at a block size of 5 msec and is placed in thread 5A. A third port operates at a block size of 1 msec and is placed in thread 1B.
Large block sizes lead to more efficient operation. You should restrict the small block sizes (0.25 and 0.5 msec) for use cases that require low latency. Other ports doing non-latency sensitive operations (like radio or Bluetooth), should use larger block sizes.
If you stop a port, it will stop the audio DMA and interrupts. The DMA memory is freed up. When you start the port, DMA memory is reallocated and DMA interrupts start again. SA ports will restart and be time aligned to the SM port. SU ports will restart and resynchronize themselves to the SM port.
The SM, SA, and SU ports have a single block size argument. This block size is used to set the block size of the DMA interrupt and also the block size at the output (or input) audio pins in Audio Weaver.
The AS port has separate sample rates and block sizes for the device configuration and the Audio Weaver configuration. After stopping an AS device, you can change the device block size and sample rate, and these new values will be used when the port is restarted. This feature is specifically for interfacing with Bluetooth devices.
TDM ports can only be accessed from the Hexagon DSPs. They are not available on the Arm.
On the SA8255, the DSPs are all part of the early audio boot sequence and thus all TDM ports must be initialized during early audio. On Nordy, only DSP0 is part of the early boot sequence. TDM ports can be on DSP0 and on DSP1 or DSP2 which are part of the late boot sequence.
Troubleshooting
Asynchronous TDM Input Port
ASRC Overruns occur. Should not happen in normal operation, but can happen if:
The device being interfaced to is the clock master, and the sample rate of the device does not match deviceSampleRate.
The module is no longer “Active” in Audio Weaver. Pumping does not occur and the ASRC jitter buffer is not emptying.
ASRC Underruns occur.
The device being interfaced to is the clock master, and the sample rate of the device does not match deviceSampleRate.
This can also happen if Audio Weaver Weaver is pumping and there is not enough data in the ASRC’s jitter buffer. You should increase the ASRC Prefill Level on the inspector. Set the level so that there is enough data to generate 2 output blocks of data at the output Audio Weaver block size and sample rate.
Asynchronous TDM Output Port
ASRC Overruns. Should never happen.
ASRC Underruns. Should never happen.
FIFO Overruns
The device being interfaced to is the clock master, and the sample rate of the device does not match deviceSampleRate.
FIFO Underruns
The device being interfaced to is the clock master, and the sample rate of the device does not match deviceSampleRate.
Increase the FIFO prefill level so that it equals at least 2 deviceBlockSize samples.