Puretone Unidirectional

Description

The Puretone Unidirectional application is an audio example derived from the Puretone Headset application. It uses the SPARK Wireless Core to transmit a stereo audio stream with 96kHz/24-bit depth from the Coordinator to the Node (the Main Channel). Unlike the Puretone Headset, there is no back channel audio — audio flows in one direction only, from Coordinator to Node. When the link quality degrades, it will automatically switch to fallback mode which involves multiple fallback processing stages on both sides. The audio stream will revert to default once the link quality returns to normal.

A bidirectional data link is used for transmitting user data (button status) and link margin information from the Node back to the Coordinator, enabling dynamic fallback decisions.

The application can either use the analog audio codec of the EVKs or the USB audio interface to receive and transmit audio data. Different compilation flags are required to select the desired audio interface.

To compile the application for USB audio, set the “USB_AUDIO_ENABLED”: “ON” flag in the application’s CMake preset cacheVariables section.

     {
         "name": "puretone-unidirectional-sr11xx-quasar-usb_audio",
         "inherits": ["base","quasar"],
         "description": "Puretone Unidirectional example for SR11xx with Quasar USB AUDIO",
         "cacheVariables": {
             "APP": "Puretone-Unidirectional",
             "TRANSCEIVER": "SR1100",
             "USB_AUDIO_ENABLED": "ON"
         }
     },

Note

This application supports only SR1120 transceiver operating with the Quasar platform.

Behavior

Audio Configuration

The application can be configured using the sac_cfg.h file located in the config folder.

Only the OTA bit depth can be tuned without modifying the application code:

  • MAIN_CHANNEL_OTA_UNCOMPRESSED_BIT_DEPTH: Set to 20 or 24 (fallback modes 0 & 1).

/* **** Main Channel Settings. **** */

#define MAIN_CHANNEL_SAMPLE_RATE_HZ 96000
#define MAIN_CHANNEL_SAMPLE_COUNT   40
#define MAIN_CHANNEL_CHANNEL_COUNT  2
#define MAIN_CHANNEL_BIT_DEPTH      24
/* Maximum Latency. */
#define MAIN_CHANNEL_MAX_LATENCY_MS 15
/* Fallback modes Latency. */
#define MAIN_CHANNEL_FBK_0_LATENCY_MS 5
#define MAIN_CHANNEL_FBK_1_LATENCY_MS 7
#define MAIN_CHANNEL_FBK_2_LATENCY_MS 10
#define MAIN_CHANNEL_FBK_3_LATENCY_MS 15
/* Fallback modes sample count. */
#define MAIN_CHANNEL_FBK_0_SAMPLE_COUNT 40
#define MAIN_CHANNEL_FBK_1_SAMPLE_COUNT 34
#define MAIN_CHANNEL_FBK_2_SAMPLE_COUNT 34
#define MAIN_CHANNEL_FBK_3_SAMPLE_COUNT 46

/* A header is added to audio samples during fallback. */
#define MAIN_CHANNEL_FALLBACK_HEADER_SIZE sizeof(sac_header_t)
/* A header is added to compressed audio samples during fallback. */
#define MAIN_CHANNEL_FALLBACK_COMPRESSION_HEADER_SIZE \
    (sizeof(sac_header_t) + SAC_COMPRESSION_HEADER_SIZE(MAIN_CHANNEL_CHANNEL_COUNT))

/* Calculated values. */
#define MAIN_CHANNEL_SWC_PAYLOAD_SIZE \
    SAC_CALCULATE_PAYLOAD_SIZE(MAIN_CHANNEL_SAMPLE_COUNT, MAIN_CHANNEL_CHANNEL_COUNT, MAIN_CHANNEL_BIT_DEPTH)
#define MAIN_CHANNEL_I2S_PAYLOAD_SIZE \
    SAC_CALCULATE_PAYLOAD_SIZE(MAIN_CHANNEL_SAMPLE_COUNT, MAIN_CHANNEL_CHANNEL_COUNT, I2S_DMA_BIT_DEPTH)
/* Size of the latency queue used by the Audio Core for the main channel. */
#define MAIN_CHANNEL_LATENCY_QUEUE_SIZE                                                                        \
    SAC_CALCULATE_LATENCY_QUEUE_SIZE(MAIN_CHANNEL_MAX_LATENCY_MS, CODEC_LATENCY_MS, MAIN_CHANNEL_SAMPLE_COUNT, \
                                     MAIN_CHANNEL_SAMPLE_RATE_HZ)
#define MAIN_CHANNEL_FBK_0_LATENCY_QUEUE_SIZE                                                                    \
    SAC_CALCULATE_LATENCY_QUEUE_SIZE(MAIN_CHANNEL_FBK_0_LATENCY_MS, CODEC_LATENCY_MS, MAIN_CHANNEL_SAMPLE_COUNT, \
                                     MAIN_CHANNEL_SAMPLE_RATE_HZ)
#define MAIN_CHANNEL_FBK_1_LATENCY_QUEUE_SIZE                                                                    \
    SAC_CALCULATE_LATENCY_QUEUE_SIZE(MAIN_CHANNEL_FBK_1_LATENCY_MS, CODEC_LATENCY_MS, MAIN_CHANNEL_SAMPLE_COUNT, \
                                     MAIN_CHANNEL_SAMPLE_RATE_HZ)
#define MAIN_CHANNEL_FBK_2_LATENCY_QUEUE_SIZE                                                                    \
    SAC_CALCULATE_LATENCY_QUEUE_SIZE(MAIN_CHANNEL_FBK_2_LATENCY_MS, CODEC_LATENCY_MS, MAIN_CHANNEL_SAMPLE_COUNT, \
                                     MAIN_CHANNEL_SAMPLE_RATE_HZ)
#define MAIN_CHANNEL_FBK_3_LATENCY_QUEUE_SIZE                                                                    \
    SAC_CALCULATE_LATENCY_QUEUE_SIZE(MAIN_CHANNEL_FBK_3_LATENCY_MS, CODEC_LATENCY_MS, MAIN_CHANNEL_SAMPLE_COUNT, \
                                     MAIN_CHANNEL_SAMPLE_RATE_HZ)

/* Fallback modes payload size. */
#define MAIN_CHANNEL_FALLBACK_PAYLOAD_SIZE                                                            \
    {                                                                                                 \
        SAC_CALCULATE_PAYLOAD_SIZE(MAIN_CHANNEL_FBK_1_SAMPLE_COUNT, MAIN_CHANNEL_CHANNEL_COUNT, 24) + \
            MAIN_CHANNEL_FALLBACK_HEADER_SIZE,                                                        \
        SAC_CALCULATE_PAYLOAD_SIZE(MAIN_CHANNEL_FBK_2_SAMPLE_COUNT, MAIN_CHANNEL_CHANNEL_COUNT, 16) + \
            MAIN_CHANNEL_FALLBACK_HEADER_SIZE,                                                        \
        SAC_CALCULATE_PAYLOAD_SIZE(MAIN_CHANNEL_FBK_3_SAMPLE_COUNT, MAIN_CHANNEL_CHANNEL_COUNT,       \
                                   SAC_COMPRESSION_SAMPLE_RESOLUTION) +                               \
            MAIN_CHANNEL_FALLBACK_COMPRESSION_HEADER_SIZE,                                            \
    }

/* Accumulator settings. */
#define MAIN_CHANNEL_MAX_ACC_MUL 23
#define MAIN_CHANNEL_MAX_ACC_DIV 10

#define MAIN_CHANNEL_ACC_MUL \
    {                        \
        1,                   \
        17,                  \
        17,                  \
        23,                  \
    }
#define MAIN_CHANNEL_ACC_DIV \
    {                        \
        1,                   \
        10,                  \
        10,                  \
        10,                  \
    }

/* Fallback latency. */
#define MAIN_CHANNEL_FALLBACK_LATENCY_QUEUE_SIZE \
    {                                            \
        MAIN_CHANNEL_FBK_0_LATENCY_QUEUE_SIZE,   \
        MAIN_CHANNEL_FBK_1_LATENCY_QUEUE_SIZE,   \
        MAIN_CHANNEL_FBK_2_LATENCY_QUEUE_SIZE,   \
        MAIN_CHANNEL_FBK_3_LATENCY_QUEUE_SIZE,   \
    }

/* Fallback latency fifo size. */
#define MAIN_CHANNEL_FALLBACK_LATENCY_FIFO_SIZE                                                        \
    {                                                                                                  \
        (MAIN_CHANNEL_FBK_0_LATENCY_QUEUE_SIZE * ((MAIN_CHANNEL_BIT_DEPTH + 7) / SAC_BYTE_SIZE_BITS)), \
        (MAIN_CHANNEL_FBK_1_LATENCY_QUEUE_SIZE * ((MAIN_CHANNEL_BIT_DEPTH + 7) / SAC_BYTE_SIZE_BITS)), \
        (MAIN_CHANNEL_FBK_2_LATENCY_QUEUE_SIZE * ((MAIN_CHANNEL_BIT_DEPTH + 7) / SAC_BYTE_SIZE_BITS)), \
        (MAIN_CHANNEL_FBK_3_LATENCY_QUEUE_SIZE * ((MAIN_CHANNEL_BIT_DEPTH + 7) / SAC_BYTE_SIZE_BITS)), \
    }

Audio Interface

The application receives audio from the line in of the Coordinator, utilizes the audio codec to transmit it over the I2S line using DMA transfers, and outputs the audio to the headphone out of the Node.

The audio core pipeline processes audio samples coming from the I2S to format them to be sent over the air using the SWC. The I2S end of transfer callback and the SWC transmission success callback will trigger the audio processing to synchronize the I2S production rate and the SWC consumption rate.

Audio application timings in normal operation

Figure 37: Audio application timings in normal operation.

The Audio Task row shows when swc_connection_send() actually enqueues the packet. The event that decides which slot the packet catches is the connection’s frame preparation (prepare_frame), which selects and latches the payload for the next assigned slot. Frame preparation runs in the SPI DMA ISR context (see the prepare_frame step in the Wireless Core timing diagram).

Each transmit slot first dequeues the previously acknowledged packet, then pulls the next one from the SWC queue to prepare it, so the queue must be able to hold at least two entries to track both the in-flight and the next packet.

If the Audio Task enqueues after that preparation point, the packet misses the slot, which ships empty, and it must wait for the following preparation, adding one inter-opportunity gap to its wireless latency; see Wireless Latency for the corresponding formulas.

When a packet transmission fails, the audio packets will accumulate in the audio consumer queue until the wireless core can transmit its payloads and free a space in its queue.

Audio application timings when a packet transmission fails

Figure 38: Audio application timings when a packet transmission fails.

The application receives audio from the USB audio interface at either 1 kHz (USB Full-Speed) or 8 kHz (USB High-Speed) depending on the capabilities of the device.

Note

When using USB audio, the host computer controls the playback. If audio playback stops on the host computer, no audio samples are received on the device. This means that the audio connection will not send any packets.

These frames are then accumulated and split into audio packets to be sent to the audio pipeline for processing before being sent OTA using the SWC. When using the USB interface, the audio samples are already formatted to packed 24-bit.

On the receiving side, the audio packets received OTA are processed and sent to the USB audio interface where a FIFO will accumulate the samples.

Note

When using USB audio, the host computer controls the recording. If the audio recording stops on the host computer, no audio samples are read from the device. This means that the USB audio transmission FIFO will not be depleted and will eventually overflow. Once the recording resumes, the FIFO will be consumed again and will stabilize to the correct level to match the expected latency.

The unidirectional data link allows for the transmission of the link margin from the Node to the Coordinator. The link margin makes it possible for the Coordinator to track the quality of the connection, thereby switching between fallback and normal modes as needed. Button status (SW2) is also sent from the Node to the Coordinator for LED mirroring.

Note

The Coordinator’s data connection is part of the synchronization design of this application. With USB audio, the audio connection stops transmitting entirely while the host is not streaming, and the Coordinator’s periodic data transmission becomes the Node’s only synchronization source, acting as the network beacon. Its period must not exceed 10 ms so that two data frames fit within the Node’s synchronization-loss timeout, tolerating one lost frame (see Sync Timeslot (Beacon)). Removing this data connection or increasing its period would cause the Node to repeatedly lose synchronization while the audio stream is idle.

The wireless schedule allocates 20 timeslots for the Coordinator transmissions and 1 timeslot for the Node. The schedule is designed to maximize bandwidth for the unidirectional audio stream from the Coordinator to the Node, with minimal bandwidth reserved for the Node’s data feedback.

In the UWB frequency range, the wireless core alternates between 4 different frequency bands at each transmission.

Application Schedule

The following diagram illustrates the general structure of the schedule used in this application.

Puretone Unidirectional schedule

Figure 39: Puretone Unidirectional Application’s Schedule.

Pairing

On boot, devices attempt to pair automatically. If unsuccessful, manual pairing can be performed afterward to use the application.

Auto Pairing:
  • On boot, devices automatically start the pairing process. RGB blinks blue twice to indicate that pairing is in progress.

  • If the pairing procedure is unsuccessful, RGB blinks red twice after 10 seconds.

  • Once successfully paired, RGB turns magenta, and the devices begin exchanging application data.

Manual Pairing:
  • Press the SW1 button on both devices to start the pairing procedure; RGB blinks blue twice when doing so.

  • If the pairing procedure is unsuccessful, RGB blinks red twice after 10 seconds.

  • Once successfully paired, RGB turns magenta, and the devices begin exchanging application data.

Unpairing:
  • When paired, pressing the SW1 button again unpairs the device; RGB blinks red twice to indicate that unpairing has been completed.

  • Unpairing causes the devices to forget their learned addresses. The devices are no longer able to exchange application data.

  • To start a new pairing procedure, both devices must be unpaired first.

Fallback

The transmitter continuously monitors the link quality. If the link quality degrades, the application will dynamically reduce the audio packet size to increase output power settings. Each fallback level progressively reduces the required air throughput by modifying the sample rate, bit depth, or compression scheme. While in fallback mode, if the link quality remains strong for a specified amount of time and the CCA try count stays below a defined threshold, the system will revert to normal mode. The thresholds for entering and exiting fallback mode differ, creating hysteresis to prevent the system from toggling frequently in conditions of marginal link quality.

Main Channel Fallback

The main channel supports three audio fallback modes.

Fallback Mode 1 - 48kHz/24-bit Uncompressed

Processing stages:

  • Audio accumulator (1.7x)

  • Downsampling from 96 kHz to 48 kHz

This mode accumulates a higher number of samples per packet then halves the sampling rate while maintaining 24-bit resolution, lowering the application’s throughput and improving link robustness. If the link quality remains strong for 5 seconds and the CCA try count stays below a defined threshold, the system will revert to normal mode.

Fallback Mode 2 - 48kHz/16-bit Uncompressed

Processing stages:

  • Audio accumulator (1.7x)

  • Downsampling from 96 kHz to 48 kHz

  • Packing to 16-bit samples

This mode further reduces throughput by decreasing bit depth from 24-bit to 16-bit. Audio quality is reduced but link margin is significantly improved. If the link quality remains strong for 4 seconds and the CCA try count stays below a defined threshold, the system will revert to normal mode.

Fallback Mode 3 - 48kHz ADPCM

Processing stages:

  • Audio accumulator (2.3x)

  • Downsampling from 96 kHz to 48 kHz

  • ADPCM compression

This mode accumulates a higher number of samples, halves the sampling rate and employs the ADPCM algorithm for audio data compression. This compression algorithm reduces audio samples by a factor of 4. This stage helps lower the application’s throughput to increase range while still ensuring relatively good audio quality. If the link quality remains strong for 2 seconds and the CCA try count stays below a defined threshold, the system will revert to normal mode.

Clock Drift Compensation (CDC)

Clock Drift Compensation (CDC) is used to adjust the timing difference between the two devices. The Coordinator is the reference clock. Therefore, for the stereo audio Main Channel stream, the Node can use its internal PLL (when hardware allows) to adjust its clock frequency to the Coordinator’s. For more information regarding CDC, refer to Clock Drift Compensation.

Variable Audio Latency per Fallback Mode

The application couples the effective audio latency to the current fallback mode. Each mode is configured with its own target latency, and the CDC on the Node dynamically drives the receive queue to the corresponding fill level whenever the mode changes. No pipeline reconfiguration is required; only the CDC target queue size is updated at runtime.

More aggressive fallback modes need more receive-side buffering because they use larger accumulated packets and lower over-the-air throughput, both of which increase jitter. The physical queue is sized once at compile time for the worst-case (highest) latency, and the CDC keeps the queue only partially filled during lower-latency modes.

Table 46: Main Channel Fallback Latency Targets

Fallback Mode

Target Latency

Notes

Normal (0)

5 ms

96 kHz / 24-bit, no accumulation

Fallback 1

7 ms

48 kHz / 24-bit, 1.7x accumulator

Fallback 2

10 ms

48 kHz / 16-bit, 1.7x accumulator

Fallback 3

15 ms

48 kHz ADPCM, 2.3x accumulator

The latency and sample-count values are defined in app/example/puretone_unidirectional/config/sac_cfg.h and can be tuned by editing the MAIN_CHANNEL_FBK_*_LATENCY_MS macros. See Clock Drift Compensation for a description of how the CDC target queue size mechanism enables this runtime latency switching.

Board User Interface

The board user interfaces are identical for the Node and the Coordinator and includes LEDs, RGB and button switches.

Table 47: Quasar Board User Interface Description

Interface

Name

Description

SW1

Pairing process

Pair, unpair, or abort the pairing process depending on the current state.

SW2

Fallback selector / Button mirror

Coordinator: Cycle through all fallback modes. Node: Mirror LED4 on Coordinator.

SW3

Volume up

Raises the received audio volume on the Node (default at 100%).

SW4

Volume down

Lowers the received audio volume on the Node.

LED1

Transmission success

Toggles every time an audio packet is successfully transmitted (Coordinator).

LED2

Reception success

Toggles every time an audio packet is successfully received (Node).

LED4

Button mirror

Turns on when the remote device presses SW2.

RGB

Pairing Event

Indicate pairing event as described in the pairing section.

Note

  • LEDs assigned to transmission or reception status are almost always on because of the high packet rate.

  • Audio volume is adjusted by the Node only using SW3 and SW4 buttons.

Certification

This application has the ability to run in Certification Mode.

When certification mode is active, a dedicated LED is activated to indicate that the mode is enabled. All activity status LEDs (transmission, reception, fallback, and payload) are suppressed so that only the certification indicator is visible.

Table 48: Certification Mode Indicator

Board

Indicator

Quasar

RGB LED steady yellow.

EVK1.4

Steady LED2.

Different levels of certification are required to test the fallback modes and data connection.

  • Depending on which mode is requested, the max_payload_size of the audio connection will be changed.

  • The order in which connections are initialized and their priority will be swapped if the data connection needs to be tested.

Activating the Certification Mode

This application is unidirectional: only the Coordinator transmits audio. The Coordinator exposes one certification mode per main-channel rate/bit-depth plus a Control Data mode. The Node has no audio transmit path, so only the Control Data certification mode is applicable on the Node.

Each certification mode must be activated independently on its own board.

Table 49: Certification Mode Activation for the Coordinator

Certification Mode

Activation Process

96kHz/24-bit Audio

Hold SW2 at startup until the LED 1 blinks once, then release.

48kHz/24-bit Audio

Hold SW2 at startup until the LED 1 blinks twice, then release.

48kHz/16-bit Audio

Hold SW2 at startup until the LED 1 blinks three times, then release.

48kHz ADPCM Audio

Hold SW2 at startup until the LED 1 blinks four times, then release.

Control Data

Hold SW2 at startup until the LED 1 blinks five times, then release.

Table 50: Certification Mode Activation for the Node

Certification Mode

Activation Process

Control Data

Hold SW2 at startup until the LED 1 blinks five times, then release.

Terminal

The following figure shows the terminal output of this application.

See Viewing the Terminal for details on how to view the terminal output.

Puretone Unidirectional Terminal Output

Figure 40: Puretone Unidirectional Terminal Output - Statistics (from left: Coordinator & Node).

See Audio Core API - Statistics and Wireless Core API - Statistics for more details.

Latency Breakdown

This application has variable latency that changes at runtime depending on link quality. As the link degrades, the system trades latency for robustness by increasing RX queue depth.

The following diagrams show the latency breakdown at each fallback level (I2S interface). Block widths are proportional to their contribution.

Puretone Mode 0 Latency

Figure 41: Mode 0 — 96 kHz/24-bit (target: 5 ms).

Puretone Mode 1 Latency

Figure 42: Mode 1 — 48 kHz/24-bit (target: 7 ms).

Puretone Mode 2 Latency

Figure 43: Mode 2 — 48 kHz/16-bit (target: 10 ms).

Puretone Mode 3 Latency

Figure 44: Mode 3 — 48 kHz/ADPCM (target: 15 ms).

Table 51: Latency by Fallback Mode

Mode

Target

RX Queue Pkts

RX Queue

Wireless (typical)

Total (typical)

0 (normal)

5 ms

6

2.5 ms

0.37 ms

~4.8 ms

1

7 ms

11

4.58 ms

0.37 ms

~6.9 ms

2

10 ms

18

7.5 ms

0.37 ms

~9.8 ms

3 (ADPCM)

15 ms

30

12.5 ms

0.37 ms

~14.8 ms

Schedule: 20 TX slots (shared audio + data via priority) of 250 us, 5.25 ms frame period. Gap pattern: 19 x 250 us + 1 x 500 us (Node RX slot break). Max gap: 500 us.

Wireless budget (constant across modes): E[wait] = 137 us, CCA = 3.1 us, airtime = 134.1 us, post-RX = 2.6 us, RX processing = 91 us.

Note

The wireless component remains constant across fallback modes. Only the RX queue depth changes, which is the mechanism by which the system absorbs increased retransmission jitter when the link quality degrades.

See Wireless Latency and Audio Latency for the formulas used in this breakdown.