diff --git a/.metadata/product.json b/.metadata/product.json
index d52dd5706..8c78fd119 100644
--- a/.metadata/product.json
+++ b/.metadata/product.json
@@ -5,9 +5,10 @@
"documentationPath": "../docs",
"includePaths": [
"../source",
+ "C:/ti/mcu_plus_sdk/source/sysconfig",
],
"components": [
-
+ "/open_pru",
],
"devices": [
"AM64x",
diff --git a/examples/makefile b/examples/makefile
index 0087eedbe..5ee2d995f 100644
--- a/examples/makefile
+++ b/examples/makefile
@@ -3,7 +3,7 @@ include ../imports.mak
SUBDIRS := \
custom_frequency_generator empty empty_c \
fft/split_radix_fft_4k_single_core fft/split_radix_fft_post_processing \
- LCD_interface logic_scope pru_emif spi_loopback \
+ LCD_interface logic_scope pru_emif pru_i2s spi_loopback \
fir multicore_scheduler rpmsg_echo_linux
# "make" or "make all" builds projects that match $(DEVICE) set in imports.mak
diff --git a/examples/pru_i2s/README.md b/examples/pru_i2s/README.md
new file mode 100644
index 000000000..6034d1287
--- /dev/null
+++ b/examples/pru_i2s/README.md
@@ -0,0 +1,464 @@
+
+
+# PRU I2S/TDM Audio Interface
+
+
+
+[Introduction](#introduction) | [Setup](#setup-details) | [Hardware](#hardware-requirements) | [Software](#software-requirements) | [Building](#building-the-project) | [Architecture](#architecture) | [Testing](#testing)
+
+## Introduction
+
+This example demonstrates the usage of PRU-ICSS to implement an I2S (Inter-IC Sound) and TDM (Time Division Multiplexing) audio interface on AM263x/AM261x processors. The PRU-ICSS subsystem emulates an I2S/TDM master, enabling transmission and reception of audio data with deterministic real-time performance.
+
+### Key Features
+- **Dual Protocol Support**: I2S (stereo) and TDM4 (4-channel) implementations
+- **Ping-Pong Buffering**: Dual 128-byte buffers for continuous audio streaming
+- **External Clock Sync**: Synchronized with external BCLK and FSYNC signals
+- **Interrupt-Driven**: Efficient buffer management with minimal CPU overhead
+- **Low Latency**: Real-time audio processing with deterministic timing
+- **Dual PRU Cores**: PRU0 for TX, PRU1 for RX
+
+### How It Works
+The PRU firmware executes on 2 PRU cores (PRU0 for Tx and PRU1 for Rx) to handle audio data streams from external sources and generate standard I2S/TDM data streams synchronized with external audio clocks (BCLK, FSYNC).
+
+**Double Buffering Technique:**
+- **RX**: Interrupt generated after receiving 128 bytes; Buffer 0 and Buffer 1 used in ping-pong fashion
+- **TX**: Interrupt generated after transmitting 128 bytes; Buffer 0 and Buffer 1 used in ping-pong fashion
+
+This ensures continuous and efficient data transmission/reception with minimal latency and overhead.
+
+---
+
+## Supported Devices
+
+| Device | Board | ICSS Instance | Status |
+|--------|-------|---------------|--------|
+| AM263x | Control Card (CC) + HSECDOCK | ICSSM0 | ✓ Tested |
+| AM261x | LaunchPad (LP) E1 | ICSSM1 | ✓ Tested |
+
+---
+
+## Setup Details
+
+### Hardware Requirements
+
+#### AM263x Control Card Setup
+**Required Equipment:**
+- AM263x Control Card (CC) [TMDSCNCD263](https://www.ti.com/tool/TMDSCNCD263)
+- TMDSHSECDOCK HSEC180 control card Baseboard Docking Station [HSECDOCK](https://www.ti.com/tool/TMDSHSECDOCK)
+- Power Supply: 5V, 3A PSU or USB Type-C AC/DC 5V/3A
+- TLV320AIC3254 Audio Codec EVM [TLV320AIC3254EVM-K](https://www.ti.com/tool/TLV320AIC3254EVM-K)
+- Function generator (for MCLK)
+- Logic analyzer (for debugging)
+
+#### AM261x LaunchPad Setup
+**Required Equipment:**
+- AM261x-LP E1 [LP-AM261](https://www.ti.com/tool/LP-AM261)
+- Power Supply: 5V, 3A PSU
+- PCM6260-Q1 Audio ADC EVM [PCM6260-Q1](https://www.ti.com/product/PCM6260-Q1)
+- Function generator (for MCLK)
+- Logic analyzer (for debugging)
+
+### Software Requirements
+
+**Development Tools:**
+- Code Composer Studio 12.8.1
+- SysConfig 1.23.1
+- MCU+ SDK AM263x 10.2
+- MCU+ SDK AM261x 10.2
+- PRU Code Generation Tools (included in CCS)
+
+**Audio Codec Software:**
+- PUREPATHCONSOLE 3 Application (for TLV320AIC3254)
+- AIC3254 01.00.00.0A [SLAC349](https://www.ti.com/tool/download/SLAC349)
+- PCM6260Q1 APP [PCM6260QEVM-SW](https://www.ti.com/secureresources/PCM6260QEVM-SW)
+
+### Hardware Connections
+
+#### AM263x CC + TLV320AIC3254 Setup
+
+
+
+**Block Diagram:**
+
+
+**Connection Steps:**
+1. **Connect AM263x CC to HSECDOCK:**
+ - AM263x CC 120 Pin Primary Card-Edge → HSECDOCK J3A
+ - AM263x CC 60 Pin Secondary Card-Edge → HSECDOCK J3B
+
+2. **Configure AIC3254 EVM:**
+ - Connect PC via USB cable to J7
+ - Set SW2: positions 1,3,6,7 ON
+ - For external audio interface: SW2.4,5 OFF
+
+3. **Audio Clock Connections:**
+ - Function generator MCLK → AIC J14.1 MCLK
+ - AIC P22.3 BCLK → HSECDOCK J8.02 (pin 123)
+ - AIC P22.7 WCLK → HSECDOCK J9.03 (pin 126)
+
+#### AM261x LP + PCM6260-Q1 Setup
+
+
+
+**Block Diagram:**
+
+
+**Connection Steps:**
+1. **Configure PCM6260-Q1 EVM:**
+ - Connect PC via USB cable
+ - Set SW2 for External ASI mode:
+ 
+
+2. **Audio Clock Connections:**
+ 
+ - Function generator (16MHz) → PCM6260 J7 MCLK
+ - PCM6260 J7 BCLK → AM261x LP J2.13
+ - PCM6260 J7 FSYNC → AM261x LP J1.5
+ - PCM6260 J7 DOUT1 → AM261x LP J2.18
+
+3. **Open PCM6260 GUI** for codec configuration
+
+> **Note:** TLV320AIC3254EVM-K can also be used with AM261x for generating external clock sources.
+
+### PRU Pin Assignments
+
+#### AM263x CC Pin Mapping
+| PRU Core | I2S Signal | PRU GPIO | Direction | HSECDOCK Pin |
+|----------|------------|----------|-----------|--------------|
+| PRU0 | BCLK | PR0_PRU0_GPIO6 | INPUT | J8.02 (123) |
+| PRU0 | FSYNC | PR0_PRU0_GPIO1 | INPUT | J9.03 (126) |
+| PRU0 | TX | PR0_PRU0_GPIO2 | OUTPUT | J8.04 (127) |
+| PRU1 | BCLK | PR0_PRU1_GPIO0 | INPUT | J8.11 (143) |
+| PRU1 | FSYNC | PR0_PRU1_GPIO1 | INPUT | J9.11 (144) |
+| PRU1 | RX | PR0_PRU1_GPIO2 | INPUT | J8.12 (145) |
+
+#### AM261x LP Pin Mapping
+| PRU Core | I2S Signal | PRU GPIO | Direction | Header Pin |
+|----------|------------|----------|-----------|------------|
+| PRU0 | BCLK | PR1_PRU0_GPIO5 | INPUT | J7.70 |
+| PRU0 | FSYNC | PR1_PRU0_GPIO6 | INPUT | J7.69 |
+| PRU0 | TX | PR1_PRU0_GPIO7 | OUTPUT | J8.72 |
+| PRU1 | BCLK | PR1_PRU1_GPIO5 | INPUT | J2.13 |
+| PRU1 | FSYNC | PR1_PRU1_GPIO9 | INPUT | J1.5 |
+| PRU1 | RX | PR1_PRU1_GPIO12 | INPUT | J2.18 |
+
+---
+
+## Project Directory Structure
+
+```
+pru_i2s/
+├── README.md # This file
+├── makefile # Top-level makefile
+├── firmware/ # PRU firmware source code
+│ ├── include/ # Shared firmware headers
+│ ├── I2S/ # I2S protocol implementation
+│ │ ├── pru_i2s_main.asm # Main firmware logic
+│ │ ├── fw_regs.asm # Register definitions
+│ │ ├── linker.cmd # Linker script
+│ │ ├── icss_pru_i2s_fw.h # Firmware register map
+│ │ ├── pru_i2s_interface.h # Interface definitions
+│ │ ├── pru_i2s_regs.h # Hardware registers
+│ │ ├── pru0_tx/ # TX firmware builds
+│ │ │ ├── am261x-lp/ # AM261x variant
+│ │ │ └── am263x-cc/ # AM263x variant
+│ │ └── pru1_rx/ # RX firmware builds
+│ │ ├── am261x-lp/
+│ │ └── am263x-cc/
+│ └── TDM4/ # TDM4 protocol (parallel structure)
+│ └── (same as I2S)
+├── driver/ # PRU I2S driver implementation
+│ └── pru_i2s_drv.c # Driver source (~2400 lines)
+├── include/ # Driver public headers
+│ ├── pru_i2s_drv.h # Driver API (~1000+ lines)
+│ └── pru_i2s_pruss_intc_mapping.h # INTC definitions
+├── pru_i2s_app/ # R5F host application
+│ ├── board/ # Board support files
+│ │ ├── ioexp_tca6416.c # IO expander driver
+│ │ └── ioexp_tca6416.h
+│ ├── pru_i2s_diagnostic.c # Main application
+│ ├── data.h # Test data
+│ ├── am261x-lp/r5fss0-0_freertos/
+│ └── am263x-cc/r5fss0-0_freertos/
+└── images/ # Documentation images
+```
+
+---
+
+## Building the Project
+
+### Building with Makefiles (Command Line)
+
+**Prerequisites:**
+- Set `DEVICE` environment variable in `imports.mak`
+- Ensure CCS utils are in PATH (for gmake on Windows)
+
+**Build all firmware and application:**
+```bash
+cd /path/to/open-pru
+make DEVICE=am261x # Build for AM261x
+make DEVICE=am263x # Build for AM263x
+```
+
+**Build only firmware:**
+```bash
+cd examples/pru_i2s
+make DEVICE=am261x # Builds 4 firmware variants (I2S + TDM4, PRU0 + PRU1)
+```
+
+**Clean:**
+```bash
+make DEVICE=am261x clean
+```
+
+**What gets built:**
+- 4 PRU firmware binaries per device (I2S PRU0 TX, I2S PRU1 RX, TDM4 PRU0 TX, TDM4 PRU1 RX)
+- Firmware header arrays (`.h` files for embedding in application)
+- R5F application binary (`.out` and `.appimage`)
+
+### Building with Code Composer Studio
+
+**Import Firmware Projects:**
+1. Open CCS
+2. Project → Import CCS Projects
+3. Navigate to `examples/pru_i2s/firmware/I2S/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/`
+4. Select `example.projectspec`
+5. Click Finish
+6. Repeat for other firmware variants (pru1_rx, TDM4, etc.)
+
+**Import R5F Application:**
+1. Navigate to `examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/`
+2. Import `example.projectspec`
+
+**Build Order:**
+1. Build PRU firmware first (generates header arrays)
+2. Build R5F application (includes firmware headers)
+
+**Debug Configuration:**
+Refer to MCU+ SDK documentation:
+- [AM261x SDK Guide](https://software-dl.ti.com/mcu-plus-sdk/esd/AM261X/latest/exports/docs/api_guide_am261x/CCS_PROJECTS_PAGE.html)
+- [AM263x SDK Guide](https://software-dl.ti.com/mcu-plus-sdk/esd/AM263X/latest/exports/docs/api_guide_am263x/CCS_PROJECTS_PAGE.html)
+
+---
+
+## Architecture
+
+### R5F Host Software
+
+The R5F application initializes PRU-ICSSG, downloads firmware to PRU cores, and starts execution. After firmware starts, PRUs operate independently without R5F intervention.
+
+**Software Layers:**
+```
+┌─────────────────────────────┐
+│ R5F Application │
+│ (pru_i2s_diagnostic.c) │
+├─────────────────────────────┤
+│ PRU I2S Driver │
+│ (pru_i2s_drv.c) │
+├─────────────────────────────┤
+│ MCU+ SDK Drivers │
+│ (PRUICSS, GPIO, etc.) │
+├─────────────────────────────┤
+│ SysConfig Generated │
+│ (pinmux, clock, INTC) │
+└─────────────────────────────┘
+ ↓ firmware download
+┌─────────────────────────────┐
+│ PRU0 Firmware (TX) │
+│ PRU1 Firmware (RX) │
+└─────────────────────────────┘
+```
+
+#### SysConfig Usage
+
+The R5F application uses SysConfig to configure PRUICSS:
+
+**ICSSM Configuration:**
+- Instance: ICSSM1 (AM261x) or ICSSM0 (AM263x)
+- PRU Clock: 333 MHz (maximizes processing cycles)
+
+**GPIO Pin Configuration:**
+- **PRU0 (TX):**
+ - BCLK: PRU_GPI, Rx active, Pull Down
+ - FSYNC: PRU_GPI, Rx active, Pull Down
+ - TX: PRU_GPO, Tx active, No Pull
+- **PRU1 (RX):**
+ - BCLK: PRU_GPI, Rx active, Pull Down
+ - FSYNC: PRU_GPI, Rx active, Pull Down
+ - RX: PRU_GPI, Rx active, No Pull
+
+#### Driver API Usage
+
+**Initialization:**
+```c
+PRUI2S_init() // Read firmware config, update driver tables
+PRUI2S_getInitCfg() // Get buffer sizes, sampling freq, slot width
+PRUI2S_paramsInit() // Set default parameters
+PRUI2S_open() // Clear IMEM/DMEM, init INTC, download firmware
+PRUI2S_pruGpioPadConfig() // Configure I2S signal pins
+PRUI2S_initPpBufs() // Initialize ping-pong buffers
+```
+
+**Interrupt Management:**
+```c
+PRUICSS_intcSetSysEvtChMap() // Map system events to channels
+PRUI2S_enableInt() // Enable TX/RX interrupts
+PRUI2S_disableInt() // Disable interrupts
+PRUI2S_clearInt() // Clear interrupt flags
+```
+
+### PRU Firmware Architecture
+
+#### PRU0 Transmit (TX)
+
+
+
+**Operation:**
+1. Wait for FSYNC edge
+2. Load audio data from ping-pong buffer
+3. Transmit data synchronized to BCLK
+4. Generate interrupt when buffer empty
+5. Switch to alternate buffer
+
+#### PRU1 Receive (RX)
+
+
+
+**Operation:**
+1. Wait for FSYNC edge
+2. Receive audio data synchronized to BCLK
+3. Store data in ping-pong buffer
+4. Generate interrupt when buffer full
+5. Switch to alternate buffer
+
+#### Memory Layout
+- **PRU_IMEM**: 16 KB instruction memory (firmware code)
+- **PRU_DMEM**: Data memory (ping-pong buffers, registers)
+- **PRU_SHAREDMEM**: 64 KB shared memory (communication with R5F)
+
+#### Interrupt Handling
+Interrupts trigger on:
+- TX buffer transmission complete
+- RX buffer filled
+- Buffer underrun/overrun errors
+- Clock/frame sync errors
+
+### Firmware Configuration
+
+Configurable parameters in `firmware/I2S/pru_i2s_interface.h` or `firmware/TDM4/pru_i2s_interface.h`:
+
+```c
+// Bytes per channel
+#define BYTES_TO_LOAD
+
+// Samples per slot/channel
+#define I2S_SAMPLES_PER_CHANNEL
+#define I2S_SAMPLES_PER_CHANNEL_LESS_1 (I2S_SAMPLES_PER_CHANNEL-1)
+
+// TDM channels (TDM4 only)
+#define TDM_CHANNELS
+#define MAX_TDM_CHANNELS
+```
+
+---
+
+## Testing
+
+### RX Testing Procedure
+
+**Setup:**
+1. Configure PCM6260 device with desired I2S/TDM parameters
+ 
+ 
+
+2. Play sine wave audio (e.g., 1 kHz) to PCM device microphones
+
+**Verification:**
+- Use CCS Graph tool to plot `gPPruI2s1RxBuf` data
+- Should observe sine wave pattern
+ 
+
+**Alternative:**
+- Connect external I2S/TDM signal generator to PRU1 RX pin
+- Observe captured data in `gPPruI2s1RxBuf`
+
+### TX Testing Procedure
+
+**Setup:**
+1. Store audio samples in `gPPruI2s0TxBuf`
+ - Can capture via Ethernet or other source
+
+**Verification:**
+- Probe PRU0 TX pin with logic analyzer
+- Should see I2S data signals
+- Feed signal to amplifier (e.g., TAS6424 Class-D amp)
+- Verify audio playback
+
+### Debug Tips
+
+**Common Issues:**
+- **No data received:** Check BCLK/FSYNC connections and clock source
+- **Corrupted audio:** Verify buffer sizes match firmware configuration
+- **Interrupts not firing:** Check INTC mapping and system event configuration
+- **Timing issues:** Ensure PRU clock is 333 MHz for optimal performance
+
+**CCS Debugging:**
+- Use Memory Browser to inspect ping-pong buffers
+- Set breakpoints in interrupt handlers
+- Monitor `gPPruI2s0TxBuf` and `gPPruI2s1RxBuf` in real-time
+
+---
+
+## Performance Characteristics
+
+| Metric | Value |
+|--------|-------|
+| PRU Clock | 333 MHz |
+| Buffer Size | 128 bytes (configurable) |
+| Latency | < 1 ms (ping-pong buffering) |
+| Sample Rates | 8 kHz - 192 kHz (configurable) |
+| Bit Depths | 16/24/32-bit |
+| I2S Channels | 2 (stereo) |
+| TDM4 Channels | 4 |
+
+---
+
+## Protocol Details
+
+### I2S Protocol
+- Standard I2S format
+- Left/Right channel interleaved
+- FSYNC = Word Select (LRCLK)
+- Data valid on BCLK edges
+
+### TDM4 Protocol
+- 4-channel time division multiplexing
+- Sequential channel slots
+- FSYNC marks frame boundary
+- Supports multi-microphone arrays
+
+---
+
+## References
+
+- [PRU-ICSS Documentation](https://www.ti.com/tool/PRU-ICSS)
+- [MCU+ SDK AM261x](https://www.ti.com/tool/MCU-PLUS-SDK-AM261X)
+- [MCU+ SDK AM263x](https://www.ti.com/tool/MCU-PLUS-SDK-AM263X)
+- [I2S Specification](https://www.sparkfun.com/datasheets/BreakoutBoards/I2SBUS.pdf)
+- [TLV320AIC3254 Datasheet](https://www.ti.com/product/TLV320AIC3254)
+- [PCM6260-Q1 Datasheet](https://www.ti.com/product/PCM6260-Q1)
+
+---
+
+## License
+
+See the top-level LICENSE file in the open-pru repository.
+
+---
+
+## Support
+
+For questions or issues:
+- [TI E2E Forums](https://e2e.ti.com/)
+- [open-pru GitHub Discussions](https://github.com/TexasInstruments/open-pru/discussions)
diff --git a/examples/pru_i2s/driver/pru_i2s_drv.c b/examples/pru_i2s/driver/pru_i2s_drv.c
new file mode 100644
index 000000000..8c6eaac6e
--- /dev/null
+++ b/examples/pru_i2s/driver/pru_i2s_drv.c
@@ -0,0 +1,2000 @@
+/**
+ * \file pru_i2s_drv.c
+ *
+ * \brief PRU I2S driver implementation
+ *
+ * Copyright (C) 2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+#include "pru_i2s_drv.h"
+#include
+
+/* Application calls PRUICSS_intcInit() directly (Motor Control SDK pattern) */
+
+/* Used to check status and initialization */
+static Bool gPruI2sDrvInit = FALSE;
+
+/* Number of valid configurations */
+static uint8_t gPruI2sDrvNumValidCfg = 0;
+
+/* PRU I2S objects */
+static PRUI2S_Object gPruI2sObject[PRU_I2S_MAX_NUM_INST];
+
+/* PRU I2S SW IP attributes - Minimal configuration
+ * All INTC, GPIO, and pinmux now managed by SysConfig.
+ * Only essential base configuration remains here.
+ * NOTE: Applications must call PRUI2S_setUserConfig() to configure ICSS instance
+ * and PRU core before calling PRUI2S_init().
+ */
+static PRUI2S_SwipAttrs gPruI2sSwipAttrs[PRU_I2S_MAX_NUM_INST] =
+{
+ /* Configuration 0 - Set by PRUI2S_setUserConfig() */
+ {
+ .baseAddr = 0, /* Set by PRUI2S_setUserConfig() based on ICSS instance */
+ .icssInstId = 0, /* Set by PRUI2S_setUserConfig() */
+ .pruInstId = PRUICSS_PRU0, /* Set by PRUI2S_setUserConfig() */
+ .numTxI2s = 0, /* Detected from firmware at runtime */
+ .numRxI2s = 0, /* Detected from firmware at runtime */
+ .sampFreq = 0, /* Detected from firmware at runtime */
+ .bitsPerSlot = 0, /* Detected from firmware at runtime */
+ .i2sTxHostIntNum = 0, /* Detected from firmware at runtime */
+ .i2sRxHostIntNum = 0, /* Detected from firmware at runtime */
+ .i2sErrHostIntNum = 0, /* Detected from firmware at runtime */
+ .i2sTxIcssIntcSysEvt = 0, /* Detected from firmware at runtime */
+ .i2sRxIcssIntcSysEvt = 0, /* Detected from firmware at runtime */
+ .i2sErrIcssIntcSysEvt = 0, /* Detected from firmware at runtime */
+ },
+ /* Configuration 1 - Set by PRUI2S_setUserConfig() */
+ {
+ .baseAddr = 0, /* Set by PRUI2S_setUserConfig() based on ICSS instance */
+ .icssInstId = 0, /* Set by PRUI2S_setUserConfig() */
+ .pruInstId = PRUICSS_PRU1, /* Set by PRUI2S_setUserConfig() */
+ .numTxI2s = 0, /* Detected from firmware at runtime */
+ .numRxI2s = 0, /* Detected from firmware at runtime */
+ .sampFreq = 0, /* Detected from firmware at runtime */
+ .bitsPerSlot = 0, /* Detected from firmware at runtime */
+ .i2sTxHostIntNum = 0, /* Detected from firmware at runtime */
+ .i2sRxHostIntNum = 0, /* Detected from firmware at runtime */
+ .i2sErrHostIntNum = 0, /* Detected from firmware at runtime */
+ .i2sTxIcssIntcSysEvt = 0, /* Detected from firmware at runtime */
+ .i2sRxIcssIntcSysEvt = 0, /* Detected from firmware at runtime */
+ .i2sErrIcssIntcSysEvt = 0, /* Detected from firmware at runtime */
+ }
+};
+
+/* PRU I2S configurations */
+static PRUI2S_Config gPruI2sConfig[PRU_I2S_NUM_CONFIG] =
+{
+ {
+ &gPruI2sObject[0],
+ &gPruI2sSwipAttrs[0]
+ },
+ {
+ &gPruI2sObject[1],
+ &gPruI2sSwipAttrs[1]
+ }
+};
+
+/*
+ * Sets user configuration for a PRU I2S instance
+ *
+ * This function configures the ICSS instance and PRU core for a specific
+ * configuration index. It calculates the appropriate base address based on
+ * the ICSS instance and PRU core selection.
+ *
+ * Parameters:
+ * configIdx: Configuration index (0 or 1)
+ * icssInstId: ICSS instance ID (0=ICSSM0, 1=ICSSM1)
+ * pruInstId: PRU core ID (PRUICSS_PRU0 or PRUICSS_PRU1)
+ *
+ * return: status code
+ */
+int32_t PRUI2S_setUserConfig(
+ uint8_t configIdx,
+ uint8_t icssInstId,
+ uint8_t pruInstId
+)
+{
+ PRUI2S_SwipAttrs *pSwipAttrs;
+
+ /* Validate parameters */
+ if (configIdx >= PRU_I2S_NUM_CONFIG)
+ {
+ return PRUI2S_DRV_SERR_INV_PRMS;
+ }
+
+ if (icssInstId >= PRUI2S_NUM_ICSS_INST)
+ {
+ return PRUI2S_DRV_SERR_INV_PRMS;
+ }
+
+ if ((pruInstId != PRUICSS_PRU0) && (pruInstId != PRUICSS_PRU1))
+ {
+ return PRUI2S_DRV_SERR_INV_PRMS;
+ }
+
+ /* Update attributes - baseAddr will be calculated in PRUI2S_open() once PRUICSS handle is available */
+ pSwipAttrs = gPruI2sConfig[configIdx].attrs;
+ pSwipAttrs->icssInstId = icssInstId;
+ pSwipAttrs->pruInstId = pruInstId;
+ /* Note: baseAddr is set in PRUI2S_open() using PRUICSS handle hwAttrs */
+
+ return PRUI2S_DRV_SOK;
+}
+
+/*
+ * Initializes PRU I2S driver.
+ *
+ * Must be called before any other API functions are called.
+ *
+ * Reads information from PRU0/1 FW concerning supported I2S features &
+ * updates driver Configuration table (SW IP entries). Information is read
+ * from FW pseudo registers contained in FW DMEM images.
+ *
+ * The following information is updated in each SW IP entry:
+ * - # Tx I2S
+ * - # Rx I2S
+ * - # Tx/Rx I2S
+ * - Sampling frequency
+ * - Slot width (# bits)
+ * - Tx ping/pong buffer base address
+ * - Tx/Rx buffer (ping+pong) sizes
+ * - System Event Numbers
+ * - Pins (Bclk,Fsync,Tx,Rx).
+ *
+ * Parameters:
+ * pNumValidCfg: Pointer to number of valid configurations
+ *
+ * return: status code
+ */
+int32_t PRUI2S_init(
+ uint8_t *pNumValidCfg, PRUI2S_PruFwImageInfo (*gPruFwImageInfo)[2]
+)
+{
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ int32_t status;
+ int32_t retStatus = PRUI2S_DRV_SOK;
+ uint8_t i;
+ uint8_t successfulInits = 0; /* Track successful initializations for cleanup */
+
+
+ /* Validate input parameters */
+ if (pNumValidCfg == NULL)
+ {
+ return PRUI2S_DRV_SERR_INV_PRMS;
+ }
+ if (gPruFwImageInfo == NULL)
+ {
+ *pNumValidCfg = 0;
+ return PRUI2S_DRV_SERR_INV_PRMS;
+ }
+
+
+ if (gPruI2sDrvInit == FALSE)
+ {
+
+ /* Reset valid config count at start of initialization */
+ gPruI2sDrvNumValidCfg = 0;
+
+ /*
+ Initialize PRU I2S configurations in configuration table.
+ Stop processing configurations if error occurs while
+ initializing particular configuration.
+ */
+ for (i = 0; i < PRU_I2S_NUM_CONFIG; i++)
+ {
+
+ /* Get pointers */
+ pObj = gPruI2sConfig[i].object;
+ pSwipAttrs = gPruI2sConfig[i].attrs;
+
+ /*
+ * Initialize Object
+ */
+
+ memset(pObj, 0, sizeof(PRUI2S_Object));
+ pObj->isOpen = FALSE;
+ pObj->pruIcssHandle = NULL;
+
+ /* Construct PRU instance lock */
+ status = SemaphoreP_constructMutex(&pObj->pruInstlockObj);
+
+ if (status == SystemP_SUCCESS)
+ {
+ pObj->pruInstLock = &pObj->pruInstlockObj;
+ successfulInits = i + 1; /* Track successful mutex construction */
+ }
+ else
+ {
+ retStatus = PRUI2S_DRV_SERR_INIT;
+ /* Cleanup previously constructed mutexes */
+ for (uint8_t j = 0; j < i; j++)
+ {
+ PRUI2S_Object *pCleanupObj = gPruI2sConfig[j].object;
+ if (pCleanupObj->pruInstLock != NULL)
+ {
+ SemaphoreP_destruct(&pCleanupObj->pruInstlockObj);
+ pCleanupObj->pruInstLock = NULL;
+ }
+ }
+ break;
+ }
+
+ /*
+ * Initialize SW IP using information in PRU images.
+ *
+ * Currently up to two PRU images supported and images are mapped
+ * to PRU cores as follows:
+ * - PRU image #0 -> ICSSn/PRU0
+ * - PRU image #1 -> ICSSn/PRU1
+ * The same PRU image can be mapped to PRU0/1 by having PRU
+ * image pointers in gPruImageAddr[] point to the same image.
+ */
+
+ if ((pSwipAttrs->pruInstId == PRUICSS_PRU0) && ((*gPruFwImageInfo)[0].pPruImemImg != NULL))
+ {
+ /* Parse info in PRU image #0, update SW IP info */
+ /* Note: baseAddr will be calculated in PRUI2S_open() using PRUICSS handle */
+ status = PRUI2S_getPruFwImageInfo(&((*gPruFwImageInfo)[0]), pSwipAttrs);
+
+ if (status != SystemP_SUCCESS)
+ {
+ retStatus = PRUI2S_DRV_SERR_INIT;
+ break;
+ }
+
+ /* Set FW image pointer */
+ pObj->pPruFwImageInfo = &((*gPruFwImageInfo)[0]);
+ }
+ else if ((pSwipAttrs->pruInstId == PRUICSS_PRU1) && ((*gPruFwImageInfo)[1].pPruImemImg != NULL))
+ {
+ /* Parse info in PRU image #1, update SW IP info */
+ /* Note: baseAddr will be calculated in PRUI2S_open() using PRUICSS handle */
+ status = PRUI2S_getPruFwImageInfo(&((*gPruFwImageInfo)[1]), pSwipAttrs);
+
+ if (status != SystemP_SUCCESS)
+ {
+ retStatus = PRUI2S_DRV_SERR_INIT;
+ break;
+ }
+
+ /* Set FW image pointer */
+ pObj->pPruFwImageInfo = &((*gPruFwImageInfo)[1]);
+ }
+ else
+ {
+ /* Error, no PRU FW image for selected core type */
+ retStatus = PRUI2S_DRV_SERR_INIT_FWIMG;
+ break;
+ }
+
+ /* Check SW IP parameters */
+ status = PRUI2S_checkSwipParams(pSwipAttrs);
+
+ if (status != SystemP_SUCCESS)
+ {
+ retStatus = PRUI2S_DRV_SERR_INIT;
+ /* Cleanup previously constructed mutexes */
+ for (uint8_t j = 0; j < successfulInits; j++)
+ {
+ PRUI2S_Object *pCleanupObj = gPruI2sConfig[j].object;
+ if (pCleanupObj->pruInstLock != NULL)
+ {
+ SemaphoreP_destruct(&pCleanupObj->pruInstlockObj);
+ pCleanupObj->pruInstLock = NULL;
+ }
+ }
+ break;
+ }
+
+ gPruI2sDrvNumValidCfg++;
+ }
+
+ /* Always write output parameter */
+ *pNumValidCfg = gPruI2sDrvNumValidCfg;
+
+ if (retStatus == PRUI2S_DRV_SOK)
+ {
+ gPruI2sDrvInit = TRUE;
+ }
+
+ }
+ else
+ {
+ /* Already initialized, populate output parameter */
+ *pNumValidCfg = gPruI2sDrvNumValidCfg;
+ }
+
+
+ return retStatus;
+}
+/*
+ * De-initializes PRU I2S driver.
+ *
+ * Parameters: none
+ *
+ * return: none
+ */
+void PRUI2S_deinit(void)
+{
+ PRUI2S_Object *pObj;
+ uint8_t i;
+
+ if (gPruI2sDrvInit == TRUE)
+ {
+ for (i = 0; i < gPruI2sDrvNumValidCfg; i++)
+ {
+ /* Get object pointer */
+ pObj = gPruI2sConfig[i].object;
+
+ /* Destroy PRU instance lock */
+ if (pObj->pruInstLock != NULL)
+ {
+ SemaphoreP_destruct(&pObj->pruInstlockObj);
+ pObj->pruInstLock = NULL;
+ }
+
+ /* Reset per-object state to safe baseline */
+ pObj->pruIcssHandle = NULL;
+ pObj->isOpen = FALSE;
+ pObj->i2sTxHwiHandle = NULL;
+ pObj->i2sRxHwiHandle = NULL;
+ pObj->i2sErrHwiHandle = NULL;
+ }
+
+ /* Reset driver init state so PRUI2S_init() can be called again */
+ gPruI2sDrvNumValidCfg = 0;
+ gPruI2sDrvInit = FALSE;
+ }
+}
+
+/*
+ * Get PRUI2S SW IP attributes for use in application, e.g.
+ * - # Tx I2S
+ * - # Rx I2S
+ * - Sampling frequency
+ * - Slot width (#bits)
+ * - Tx/Rx buffer (ping+pong) size.
+ *
+ * Parameters:
+ * index Index of config to use in the Config array
+ * pCfg Pointer to SW IP in selected config
+ *
+ * return: status code
+ */
+int32_t PRUI2S_getInitCfg(
+ uint32_t index,
+ PRUI2S_SwipAttrs *pCfg
+)
+{
+ int32_t retStatus = PRUI2S_DRV_SOK;
+
+ if (index < gPruI2sDrvNumValidCfg)
+ {
+ *pCfg = gPruI2sSwipAttrs[index];
+ }
+ else
+ {
+ retStatus = PRUI2S_DRV_SERR_INV_PRMS;
+ }
+
+ return retStatus;
+}
+
+/*
+ * Sets PRU I2S default parameters.
+ *
+ * Parameters:
+ * pPrms Pointer to PRUI2S_Params structure to initialize
+ *
+ * return: none
+ */
+void PRUI2S_paramsInit(
+ PRUI2S_Params *pPrms
+)
+{
+ /* PRUICSS handle - must be set by application */
+ pPrms->pruicss_handle = NULL;
+
+ /* Buffer configuration */
+ pPrms->rxPingPongBaseAddr = 0;
+ pPrms->txPingPongBaseAddr = 0;
+ pPrms->pingPongBufSz = 0;
+
+ /* Interrupt priorities */
+ pPrms->i2sTxIntrPri = DEF_I2S_INTR_PRI;
+ pPrms->i2sRxIntrPri = DEF_I2S_INTR_PRI;
+ pPrms->i2sErrIntrPri = DEF_I2S_ERR_INTR_PRI;
+
+ /* Callback functions */
+ pPrms->i2sTxCallbackFxn = NULL;
+ pPrms->i2sRxCallbackFxn = NULL;
+ pPrms->i2sErrCallbackFxn = NULL;
+}
+
+/*
+ * Opens PRU I2S instance:
+ * - Clears associated ICSS IMEM/DMEM
+ * - Initializes ICSS INTC
+ * - Downloads firmware to PRU (IMEM/DMEM)
+ * - Constructs interrupts & registers interrupt callbacks.
+ *
+ * Parameters:
+ * index Index of config to use in the Config array
+ * pPrms Pointer to open parameters. If NULL is passed, then
+ * default values will be used
+ *
+ * return: A PRUI2S_Handle on success or a NULL on an error occurred
+ */
+PRUI2S_Handle PRUI2S_open(
+ uint32_t index,
+ PRUI2S_Params *pPrms
+)
+{
+ PRUI2S_Config *pCfg;
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ PRUI2S_Handle handle = NULL;
+ HwiP_Params hwiPrms;
+ int32_t status = SystemP_SUCCESS;
+
+
+ if (index < gPruI2sDrvNumValidCfg)
+ {
+ pCfg = &gPruI2sConfig[index];
+ pObj = pCfg->object;
+ pSwipAttrs = pCfg->attrs;
+ }
+ else
+ {
+ return handle;
+ }
+
+ /* Lock instance */
+ SemaphoreP_pend(pObj->pruInstLock, SystemP_WAIT_FOREVER);
+
+ if ((pObj->isOpen == FALSE) && (pObj->pruIcssHandle == NULL))
+ {
+
+ /* Copy parameters to Object */
+ if (pPrms != NULL)
+ {
+ pObj->prms = *pPrms;
+ }
+ else
+ {
+ PRUI2S_paramsInit(&pObj->prms);
+ }
+
+ /* Store PRUICSS handle in object */
+ pObj->pruIcssHandle = pObj->prms.pruicss_handle;
+
+ /* Validate PRUICSS handle */
+ if (pObj->pruIcssHandle == NULL)
+ {
+ status = PRUI2S_DRV_SERR_INV_PRMS;
+ goto fail;
+ }
+
+ if (status == SystemP_SUCCESS)
+ {
+ /* Get PRU ICSS hardware attributes */
+ PRUICSS_HwAttrs *hwAttrs = (PRUICSS_HwAttrs *)(pObj->pruIcssHandle->hwAttrs);
+
+ if (hwAttrs == NULL)
+ {
+ status = PRUI2S_DRV_SERR_INV_PRMS;
+ }
+ else
+ {
+ /* Calculate base address from PRUICSS handle based on PRU instance */
+ uint32_t dmemBaseAddr;
+
+ if (pSwipAttrs->pruInstId == PRUICSS_PRU0)
+ {
+ dmemBaseAddr = (uint32_t)(hwAttrs->pru0DramBase);
+ }
+ else if (pSwipAttrs->pruInstId == PRUICSS_PRU1)
+ {
+ dmemBaseAddr = (uint32_t)(hwAttrs->pru1DramBase);
+ }
+ else
+ {
+ status = PRUI2S_DRV_SERR_INV_PRMS;
+ }
+
+ if (status == SystemP_SUCCESS)
+ {
+ /* Add firmware register base offset */
+ pSwipAttrs->baseAddr = dmemBaseAddr + ICSS_PRUI2S_FW_REG_BASE;
+
+ /* Translate to local address if needed */
+ pSwipAttrs->baseAddr = (uint32_t)AddrTranslateP_getLocalAddr(pSwipAttrs->baseAddr);
+ }
+ }
+ }
+
+ /* Check parameters are valid */
+ if (status == SystemP_SUCCESS)
+ {
+ status = PRUI2S_checkOpenParams(pSwipAttrs, &pObj->prms);
+ }
+
+ if (status != SystemP_SUCCESS)
+ {
+ goto fail;
+ }
+ }
+
+ if (status == SystemP_SUCCESS)
+ {
+ /* Construct interrupts */
+ if (pObj->prms.i2sTxCallbackFxn != NULL)
+ {
+ HwiP_Params_init(&hwiPrms);
+ hwiPrms.intNum = pSwipAttrs->i2sTxHostIntNum;
+ hwiPrms.callback = pObj->prms.i2sTxCallbackFxn;
+ hwiPrms.priority = pObj->prms.i2sTxIntrPri;
+ hwiPrms.args = (void *)pCfg;
+ status = HwiP_construct(&pObj->i2sTxHwiObj, &hwiPrms);
+ if (status == SystemP_SUCCESS)
+ {
+ pObj->i2sTxHwiHandle = &pObj->i2sTxHwiObj;
+ }
+ }
+
+ if (status == SystemP_SUCCESS && pObj->prms.i2sRxCallbackFxn != NULL)
+ {
+ HwiP_Params_init(&hwiPrms);
+ hwiPrms.intNum = pSwipAttrs->i2sRxHostIntNum;
+ hwiPrms.callback = pObj->prms.i2sRxCallbackFxn;
+ hwiPrms.priority = pObj->prms.i2sRxIntrPri;
+ hwiPrms.args = (void *)pCfg;
+ status = HwiP_construct(&pObj->i2sRxHwiObj, &hwiPrms);
+ if (status == SystemP_SUCCESS)
+ {
+ pObj->i2sRxHwiHandle = &pObj->i2sRxHwiObj;
+ }
+ }
+
+ if (status == SystemP_SUCCESS && pObj->prms.i2sErrCallbackFxn != NULL)
+ {
+ HwiP_Params_init(&hwiPrms);
+ hwiPrms.intNum = pSwipAttrs->i2sErrHostIntNum;
+ hwiPrms.callback = pObj->prms.i2sErrCallbackFxn;
+ hwiPrms.priority = pObj->prms.i2sErrIntrPri;
+ hwiPrms.args = (void *)pCfg;
+ status = HwiP_construct(&pObj->i2sErrHwiObj, &hwiPrms);
+ if (status == SystemP_SUCCESS)
+ {
+ pObj->i2sErrHwiHandle = &pObj->i2sErrHwiObj;
+ }
+ }
+ }
+
+ if (status == SystemP_SUCCESS)
+ {
+ /* Initialize PRU */
+ status = PRUI2S_initPru(pCfg);
+
+ /* Initialize PRU I2S FW */
+ if (status == SystemP_SUCCESS)
+ {
+ status = PRUI2S_initFw(pCfg);
+ }
+
+ /* Initialize ping/pong buffers */
+ if (status == SystemP_SUCCESS)
+ {
+ status = PRUI2S_initPpBufs(pCfg);
+ }
+ }
+
+ if (status == SystemP_SUCCESS)
+ {
+ pObj->isOpen = TRUE;
+ handle = (PRUI2S_Handle)pCfg;
+ goto done;
+ }
+
+fail:
+ /* Destruct any HWIs constructed so far and reset object state */
+ if (pObj->i2sTxHwiHandle != NULL)
+ {
+ HwiP_destruct(&pObj->i2sTxHwiObj);
+ pObj->i2sTxHwiHandle = NULL;
+ }
+ if (pObj->i2sRxHwiHandle != NULL)
+ {
+ HwiP_destruct(&pObj->i2sRxHwiObj);
+ pObj->i2sRxHwiHandle = NULL;
+ }
+ if (pObj->i2sErrHwiHandle != NULL)
+ {
+ HwiP_destruct(&pObj->i2sErrHwiObj);
+ pObj->i2sErrHwiHandle = NULL;
+ }
+ /* Reset pruIcssHandle so a future open can retry */
+ pObj->pruIcssHandle = NULL;
+
+done:
+ /* Unlock instance */
+ SemaphoreP_post(pObj->pruInstLock);
+
+ return handle;
+}
+
+/* Closes PRU I2S instance:
+ * - Disables PRU
+ * - Resets PRU
+ * - Clears associated ICSS IMEM/DMEM.
+ * - Destroys interrupts.
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ *
+ * return: status code
+*/
+int32_t PRUI2S_close(
+ PRUI2S_Handle handle
+)
+{
+ PRUI2S_Config *pCfg;
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ int32_t status = SystemP_SUCCESS;
+ int32_t retStatus = PRUI2S_DRV_SOK;
+
+ /* Get pointers */
+ pCfg = (PRUI2S_Config *)handle;
+ pObj = pCfg->object;
+ pSwipAttrs = pCfg->attrs;
+
+ /* Lock instance */
+ SemaphoreP_pend(pObj->pruInstLock, SystemP_WAIT_FOREVER);
+
+ /*
+ * Destroy interrupts
+ */
+ if (pObj->i2sTxHwiHandle != NULL)
+ {
+ /* Disable I2S Tx interrupt - check handle is valid */
+ if (pObj->pruIcssHandle != NULL)
+ {
+ status = PRUICSS_disableEvent(pObj->pruIcssHandle, pSwipAttrs->i2sTxIcssIntcSysEvt);
+ }
+ else
+ {
+ status = SystemP_SUCCESS; /* Skip if handle not initialized */
+ }
+
+ if ((status == SystemP_SUCCESS) && (pObj->pruIcssHandle != NULL))
+ {
+ /* Clear I2S Tx pending interrupts */
+ status = PRUICSS_clearEvent(pObj->pruIcssHandle, pSwipAttrs->i2sTxIcssIntcSysEvt);
+ }
+
+ if (status == SystemP_SUCCESS)
+ {
+ /* Destroy I2S Tx interrupt */
+ HwiP_destruct(&pObj->i2sTxHwiObj);
+ pObj->i2sTxHwiHandle = NULL;
+ }
+ }
+
+ if ((status == SystemP_SUCCESS) && (pObj->i2sRxHwiHandle != NULL))
+ {
+ /* Disable I2S Rx interrupt - check handle is valid */
+ if (pObj->pruIcssHandle != NULL)
+ {
+ status = PRUICSS_disableEvent(pObj->pruIcssHandle, pSwipAttrs->i2sRxIcssIntcSysEvt);
+ }
+ else
+ {
+ status = SystemP_SUCCESS; /* Skip if handle not initialized */
+ }
+
+ if ((status == SystemP_SUCCESS) && (pObj->pruIcssHandle != NULL))
+ {
+ /* Clear I2S Rx pending interrupts */
+ status = PRUICSS_clearEvent(pObj->pruIcssHandle, pSwipAttrs->i2sRxIcssIntcSysEvt);
+ }
+
+ if (status == SystemP_SUCCESS)
+ {
+ /* Destroy I2S Rx interrupt */
+ HwiP_destruct(&pObj->i2sRxHwiObj);
+ pObj->i2sRxHwiHandle = NULL;
+ }
+ }
+
+ if ((status == SystemP_SUCCESS) && (pObj->i2sErrHwiHandle != NULL))
+ {
+ /* Disable I2S error interrupt - check handle is valid */
+ if (pObj->pruIcssHandle != NULL)
+ {
+ status = PRUICSS_disableEvent(pObj->pruIcssHandle, pSwipAttrs->i2sErrIcssIntcSysEvt);
+ }
+ else
+ {
+ status = SystemP_SUCCESS; /* Skip if handle not initialized */
+ }
+
+ /* Clear I2S error pending interrupts */
+ if ((status == SystemP_SUCCESS) && (pObj->pruIcssHandle != NULL))
+ {
+ /* Clear I2S pending interrupts */
+ status = PRUICSS_clearEvent(pObj->pruIcssHandle, pSwipAttrs->i2sErrIcssIntcSysEvt);
+ }
+
+ if (status == SystemP_SUCCESS)
+ {
+ /* Destroy I2S error interrupt */
+ HwiP_destruct(&pObj->i2sErrHwiObj);
+ pObj->i2sErrHwiHandle = NULL;
+ }
+ }
+
+ if (status == SystemP_SUCCESS)
+ {
+ /* Deinitialize PRU - only if handle was initialized */
+ if (pObj->pruIcssHandle != NULL)
+ {
+ status = PRUI2S_deinitPru(pCfg);
+ }
+ }
+
+ if (status == SystemP_SUCCESS)
+ {
+ /* Mark Object as closed */
+ pObj->isOpen = FALSE;
+ }
+
+ /* Unlock instance */
+ SemaphoreP_post(pObj->pruInstLock);
+
+ if (status == SystemP_FAILURE)
+ {
+ retStatus = PRUI2S_DRV_SERR_CLOSE;
+ }
+
+ return retStatus;
+}
+
+/*
+ * Enables PRU I2S instance
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ *
+ * return: status code
+ */
+int32_t PRUI2S_enable(
+ PRUI2S_Handle handle
+)
+{
+ PRUI2S_Config *pCfg;
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ int32_t status;
+ int32_t retStatus = PRUI2S_DRV_SOK;
+
+ /* Get pointers */
+ pCfg = (PRUI2S_Config *)handle;
+ pObj = pCfg->object;
+ pSwipAttrs = pCfg->attrs;
+
+ status = PRUICSS_enableCore(pObj->pruIcssHandle, pSwipAttrs->pruInstId);
+ if (status != SystemP_SUCCESS) {
+ retStatus = PRUI2S_DRV_SERR_PRU_EN;
+ }
+
+ return retStatus;
+}
+
+/*
+ * Initializes IO Buffer with default parameters.
+ * Same IO Buffer stucture used for write and read.
+ *
+ * Parameters:
+ * pIoBuf Pointer to PRUI2S_IoBuf structure to initialize
+ *
+ * return: none
+ */
+void PRUI2S_ioBufInit(
+ PRUI2S_IoBuf *pIoBuf
+)
+{
+ pIoBuf->ioBufAddr = NULL;
+}
+
+/*
+ * Writes I2S Tx data buffer to current PRU FW I2S Tx buffer (ping or pong).
+ * I2S Tx data buffer in interleaved format, i.e. no format change.
+ * - PRU FW I2S Tx buffer is located in ICSS memory.
+ * - PRU FW I2S Tx buffer address & length are contained in FW build
+ * (and SW IP attributes after call to PRUI2S_Init()).
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * pIoBuf Pointer to PRUI2S_IoBuf structure to use for write
+ *
+ * return: status code
+ */
+int32_t PRUI2S_write(
+ PRUI2S_Handle handle,
+ PRUI2S_IoBuf *pIoBuf
+)
+{
+ PRUI2S_Config *pCfg;
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ uint8_t *dstAddr;
+ uint8_t txPingPongSel;
+ uint16_t size;
+ uint8_t regVal;
+ int32_t retStatus = PRUI2S_DRV_SOK;
+
+ if (pIoBuf->ioBufAddr != NULL)
+ {
+ /* Get pointers */
+ pCfg = (PRUI2S_Config *)handle;
+ pObj = pCfg->object;
+ pSwipAttrs = pCfg->attrs;
+
+ /* Copy Tx data to ping or pong buffer */
+ txPingPongSel = HW_RD_REG8(pSwipAttrs->baseAddr + FW_REG_TX_PING_PONG_SEL);
+ txPingPongSel &= TX_PING_PONG_SEL_BF_TX_PING_PONG_SEL_MASK;
+ size = pObj->prms.pingPongBufSz/2;
+ /* Validate buffer size is even and non-zero */
+ if ((pObj->prms.pingPongBufSz == 0) || ((pObj->prms.pingPongBufSz & 0x1U) != 0U))
+ {
+ return PRUI2S_DRV_SERR_INV_PRMS;
+ }
+ dstAddr = (uint8_t *)pObj->txPingPongBuf;
+ if (txPingPongSel == PING_PONG_SEL_PONG)
+ {
+ dstAddr += size;
+ }
+ /* Ensure destination within allocated range */
+ if ((dstAddr < (uint8_t *)pObj->txPingPongBuf) || (dstAddr + size > ((uint8_t *)pObj->txPingPongBuf + pObj->prms.pingPongBufSz)))
+ {
+ return PRUI2S_DRV_SERR_INV_PRMS;
+ }
+ memcpy(dstAddr, (uint8_t *)pIoBuf->ioBufAddr, size);
+
+ #ifdef _DBG_TX_PP_CAP
+ gTxPpSelCapBuf[gTxPpCapBufIdx] = txPingPongSel;
+ gTxPpSrcAddrCapBuf[gTxPpCapBufIdx] = (uint32_t)pIoBuf->ioBufAddr;
+ gTxPpDstAddrCapBuf[gTxPpCapBufIdx] = (uint32_t)dstAddr;
+ gTxPpCapBufIdx++;
+ if (gTxPpCapBufIdx >= TX_PP_CAP_BUF_SZ)
+ {
+ gTxPpCapBufIdx = 0;
+ }
+ #endif
+
+ /* Set Tx buffer full status */
+ regVal = HW_RD_REG8(pSwipAttrs->baseAddr + FW_REG_TX_PING_PONG_STAT);
+ if (txPingPongSel == PING_PONG_SEL_PING)
+ {
+ regVal |= 1 << TX_PING_PONG_STAT_BF_TX_PING_STAT_SHIFT;
+ HW_WR_REG8(pSwipAttrs->baseAddr + FW_REG_TX_PING_PONG_STAT, regVal);
+ }
+ else /* PING_PONG_SEL_PONG */
+ {
+ regVal |= 1 << TX_PING_PONG_STAT_BF_TX_PONG_STAT_SHIFT;
+ HW_WR_REG8(pSwipAttrs->baseAddr + FW_REG_TX_PING_PONG_STAT, regVal);
+ }
+ }
+ else
+ {
+ retStatus = PRUI2S_DRV_SERR_INV_PRMS;
+ }
+
+ return retStatus;
+}
+
+/*
+ * Reads I2S Rx data buffer from current PRU FW I2S Rx buffer (ping or pong).
+ * I2S Rx data buffer in interleaved format, i.e. no format change.
+ * - PRU FW I2S Rx buffer location is determined by application.
+ * - PRU FW I2S Rx buffer length is contained in FW build
+ * (and SW IP attributes after call to PRUI2S_Init()).
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * pIoBuf Pointer to PRUI2S_IoBuf structure to use for read
+ *
+ * return: status code
+ */
+int32_t PRUI2S_read(
+ PRUI2S_Handle handle,
+ PRUI2S_IoBuf *pIoBuf
+)
+{
+ PRUI2S_Config *pCfg;
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ uint8_t *srcAddr;
+ uint8_t rxPingPongSel;
+ uint16_t size;
+ uint8_t regVal;
+ int32_t retStatus = PRUI2S_DRV_SOK;
+
+ if (pIoBuf->ioBufAddr != NULL)
+ {
+ /* Get pointers */
+ pCfg = (PRUI2S_Config *)handle;
+ pObj = pCfg->object;
+ pSwipAttrs = pCfg->attrs;
+
+ /* Copy Rx data to ping or pong buffer */
+ rxPingPongSel = HW_RD_REG8(pSwipAttrs->baseAddr + FW_REG_RX_PING_PONG_SEL);
+ rxPingPongSel &= RX_PING_PONG_SEL_BF_RX_PING_PONG_SEL_MASK;
+ size = pObj->prms.pingPongBufSz/2;
+ srcAddr = (uint8_t *)pObj->rxPingPongBuf;
+ if (rxPingPongSel == PING_PONG_SEL_PONG)
+ {
+ srcAddr += size;
+ }
+ memcpy((uint8_t *)pIoBuf->ioBufAddr, srcAddr, size);
+
+ #ifdef _DBG_RX_PP_CAP
+ gRxPpSelCapBuf[gRxPpCapBufIdx] = rxPingPongSel;
+ gRxPpSrcAddrCapBuf[gRxPpCapBufIdx] = (uint32_t)srcAddr;
+ gRxPpDstAddrCapBuf[gRxPpCapBufIdx] = (uint32_t)pIoBuf->ioBufAddr;
+ gRxPpCapBufIdx++;
+ if (gRxPpCapBufIdx >= RX_PP_CAP_BUF_SZ)
+ {
+ gRxPpCapBufIdx = 0;
+ }
+ #endif
+
+ /* Set Rx buffer empty status */
+ regVal = HW_RD_REG8(pSwipAttrs->baseAddr + FW_REG_RX_PING_PONG_STAT);
+ if (rxPingPongSel == PING_PONG_SEL_PING)
+ {
+ regVal &= ~(1 << RX_PING_PONG_STAT_BF_RX_PING_STAT_SHIFT);
+ HW_WR_REG8(pSwipAttrs->baseAddr + FW_REG_RX_PING_PONG_STAT, regVal);
+ }
+ else /* PING_PONG_SEL_PONG */
+ {
+ regVal &= ~(1 << RX_PING_PONG_STAT_BF_RX_PONG_STAT_SHIFT);
+ HW_WR_REG8(pSwipAttrs->baseAddr + FW_REG_RX_PING_PONG_STAT, regVal);
+ }
+ }
+ else
+ {
+ retStatus = PRUI2S_DRV_SERR_INV_PRMS;
+ }
+
+ return retStatus;
+}
+
+/*
+ * Initializes conversion IO Buffer with default parameters.
+ *
+ * Parameters:
+ * pIoBuf Pointer to PRUI2S_IoBufC structure to initialize
+ *
+ * return: none
+ */
+void PRUI2S_ioBufCInit(
+ PRUI2S_IoBufC *pIoBufC
+)
+{
+ uint8_t i;
+
+ for (i = 0; i < PRUI2S_MAX_I2S; i++)
+ {
+ pIoBufC->ioBufLAddr[i] = NULL;
+ pIoBufC->ioBufRAddr[i] = NULL;
+ }
+}
+
+/*
+ * Writes I2S Tx data buffers to current PRU FW I2S Tx buffer (ping or pong).
+ * I2S Tx data buffers in non-interleaved format, buffers are written to
+ * current I2S Tx buffer (ping or ping) in interleaved format.
+ * - PRU FW I2S Tx buffer is located in ICSS memory.
+ * - PRU FW I2S Tx buffer address & length are contained in FW build
+ * (and SW IP attributes after call to PRUI2S_Init()).
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * pIoBufC Pointer to PRUI2S_IoBufC structure to use for write
+ *
+ * return: status code
+ */
+int32_t PRUI2S_writeC(
+ PRUI2S_Handle handle,
+ PRUI2S_IoBufC *pIoBufC
+)
+{
+ PRUI2S_Config *pCfg;
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ uint8_t numTxI2s; /* number of Tx I2S */
+ uint8_t numTxCh; /* number of Tx channels */
+ uint8_t bytesPerSlot; /* number of Tx bytes per slot */
+ uint16_t numSlots; /* number of Tx slots */
+ int16_t *pSrc16b, *pDst16b;
+ int32_t *pSrc32b, *pDst32b;
+ uint8_t i;
+ uint16_t j;
+ int32_t retStatus = PRUI2S_DRV_SOK;
+
+ /* Get pointers */
+ pCfg = (PRUI2S_Config *)handle;
+ pObj = pCfg->object;
+ pSwipAttrs = pCfg->attrs;
+
+ /* Get number of Tx I2S */
+ numTxI2s = pSwipAttrs->numTxI2s;
+
+ /* Check IO buffer parameter */
+ for (i = 0; i < numTxI2s; i++)
+ {
+ if ((pIoBufC->ioBufLAddr[i] == NULL) ||
+ (pIoBufC->ioBufRAddr[i] == NULL))
+ {
+ retStatus = PRUI2S_DRV_SERR_INV_PRMS;
+ break;
+ }
+ }
+
+ if (retStatus == PRUI2S_DRV_SOK)
+ {
+ /* Calculate bytes per slot, number of channels, number of slots */
+ bytesPerSlot = pSwipAttrs->bitsPerSlot / 8;
+ numTxCh = 2*numTxI2s;
+ numSlots = pObj->prms.pingPongBufSz / (numTxCh * bytesPerSlot);
+
+ if (pSwipAttrs->bitsPerSlot == PRUI2S_BITS_PER_SLOT_16)
+ {
+ /* Interleave Left channel data */
+ for (i = 0; i < numTxI2s; i++)
+ {
+ pSrc16b = (int16_t *)pIoBufC->ioBufLAddr[i];
+ pDst16b = (int16_t *)pObj->txPingPongBuf;
+ pDst16b += i;
+
+ for (j = 0; j < numSlots; j++)
+ {
+ *pDst16b = *pSrc16b;
+ pSrc16b++;
+ pDst16b += numTxCh;
+ }
+ }
+
+ /* Interleave Right channel data */
+ for (i = 0; i < numTxI2s; i++)
+ {
+ pSrc16b = (int16_t *)pIoBufC->ioBufRAddr[i];
+ pDst16b = (int16_t *)pObj->txPingPongBuf;
+ pDst16b += numTxI2s+i;
+ for (j = 0; j < numSlots; j++)
+ {
+ *pDst16b = *pSrc16b;
+ pSrc16b++;
+ pDst16b += numTxCh;
+ }
+ }
+ }
+ else if (pSwipAttrs->bitsPerSlot == PRUI2S_BITS_PER_SLOT_32)
+ {
+ /* Interleave Left channel data */
+ for (i = 0; i < numTxI2s; i++)
+ {
+ pSrc32b = (int32_t *)pIoBufC->ioBufLAddr[i];
+ pDst32b = (int32_t *)pObj->txPingPongBuf;
+ pDst32b += i;
+ for (j = 0; j < numSlots; j++)
+ {
+ *pDst32b = *pSrc32b;
+ pSrc32b++;
+ pDst32b += numTxCh;
+ }
+ }
+
+ /* Interleave Left channel data */
+ for (i = 0; i < numTxI2s; i++)
+ {
+ /* Interleave Right channel data */
+ pSrc32b = (int32_t *)pIoBufC->ioBufRAddr[i];
+ pDst32b = (int32_t *)pObj->txPingPongBuf;
+ pDst32b += numTxI2s+i;
+ for (j = 0; j < numSlots; j++)
+ {
+ *pDst32b = *pSrc32b;
+ pSrc32b++;
+ pDst32b += numTxCh;
+ }
+ }
+ }
+ }
+
+ return retStatus;
+}
+
+/*
+ * Reads I2S Rx data buffer from current PRU FW I2S Rx buffer (ping or pong).
+ * I2S Rx data buffers in non-interleaved format, buffers are read from
+ * current I2S Rx buffer (ping or ping) in interleaved format.
+ * - PRU FW I2S Rx buffer location is determined by application.
+ * - PRU FW I2S Rx buffer length is contained in FW build
+ * (and SW IP attributes after call to PRUI2S_Init()).
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * pIoBufC Pointer to PRUI2S_IoBufC structure to use for read
+ *
+ * return: status code
+ */
+int32_t PRUI2S_readC(
+ PRUI2S_Handle handle,
+ PRUI2S_IoBufC *pIoBufC
+)
+{
+ PRUI2S_Config *pCfg;
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ uint8_t numRxI2s; /* number of Rx I2S */
+ uint8_t numRxCh; /* number of Rx channels */
+ uint8_t bytesPerSlot; /* number of Rx bytes per slot */
+ uint16_t numSlots; /* number of Rx slots */
+ int16_t *pSrc16b, *pDst16b;
+ int32_t *pSrc32b, *pDst32b;
+ uint8_t i;
+ uint16_t j;
+ int32_t retStatus = PRUI2S_DRV_SOK;
+
+ /* Get pointers */
+ pCfg = (PRUI2S_Config *)handle;
+ pObj = pCfg->object;
+ pSwipAttrs = pCfg->attrs;
+
+ /* Get number of Rx I2S */
+ numRxI2s = pSwipAttrs->numRxI2s;
+
+ /* Check IO buffer parameter */
+ for (i = 0; i < numRxI2s; i++)
+ {
+ if ((pIoBufC->ioBufLAddr[i] == NULL) ||
+ (pIoBufC->ioBufRAddr[i] == NULL))
+ {
+ retStatus = PRUI2S_DRV_SERR_INV_PRMS;
+ break;
+ }
+ }
+
+ if (retStatus == PRUI2S_DRV_SOK)
+ {
+ /* Calculate bytes per slot, number of channels, number of slots */
+ bytesPerSlot = pSwipAttrs->bitsPerSlot / 8;
+ numRxCh = 2*numRxI2s;
+ numSlots = pObj->prms.pingPongBufSz / (numRxCh * bytesPerSlot);
+
+ if (pSwipAttrs->bitsPerSlot == PRUI2S_BITS_PER_SLOT_16)
+ {
+ /* Interleave Left channel data */
+ for (i = 0; i < numRxI2s; i++)
+ {
+ pSrc16b = (int16_t *)pObj->rxPingPongBuf;
+ pSrc16b += i;
+ pDst16b = (int16_t *)pIoBufC->ioBufLAddr[i];
+ for (j = 0; j < numSlots; j++)
+ {
+ *pDst16b = *pSrc16b;
+ pSrc16b += numRxCh;
+ pDst16b++;
+ }
+ }
+
+ /* Interleave Right channel data */
+ for (i = 0; i < numRxI2s; i++)
+ {
+ pSrc16b = (int16_t *)pObj->rxPingPongBuf;
+ pSrc16b += numRxI2s+i;
+ pDst16b = (int16_t *)pIoBufC->ioBufRAddr[i];
+ for (j = 0; j < numSlots; j++)
+ {
+ *pDst16b = *pSrc16b;
+ pSrc16b += numRxCh;
+ pDst16b++;
+ }
+ }
+ }
+ else if (pSwipAttrs->bitsPerSlot == PRUI2S_BITS_PER_SLOT_32)
+ {
+ /* Interleave Left channel data */
+ for (i = 0; i < numRxI2s; i++)
+ {
+ pSrc32b = (int32_t *)pObj->rxPingPongBuf;
+ pSrc32b += i;
+ pDst32b = (int32_t *)pIoBufC->ioBufLAddr[i];
+ for (j = 0; j < numSlots; j++)
+ {
+ *pDst32b = *pSrc32b;
+ pSrc32b += numRxCh;
+ pDst32b++;
+ }
+ }
+
+ /* Interleave Right channel data */
+ for (i = 0; i < numRxI2s; i++)
+ {
+ pSrc32b = (int32_t *)pObj->rxPingPongBuf;
+ pSrc32b += numRxI2s+i;
+ pDst32b = (int32_t *)pIoBufC->ioBufRAddr[i];
+ for (j = 0; j < numSlots; j++)
+ {
+ *pDst32b = *pSrc32b;
+ pSrc32b += numRxCh;
+ pDst32b++;
+ }
+ }
+ }
+ }
+
+ return retStatus;
+}
+
+/*
+ * Gets error status.
+ * Application calls this function to obtain error status and
+ * determine cause of errors.
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * pErrStat Pointer to errot status bit-field.
+ *
+ * return: none
+ */
+void PRUI2S_getErrStat(
+ PRUI2S_Handle handle,
+ uint8_t *pErrStat
+)
+{
+ PRUI2S_Config *pCfg;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ uint8_t regVal;
+
+ /* Get pointers */
+ pCfg = (PRUI2S_Config *)handle;
+ pSwipAttrs = pCfg->attrs;
+
+ regVal = HW_RD_REG8(pSwipAttrs->baseAddr + FW_REG_ERR_STAT);
+ *pErrStat = regVal;
+}
+
+/*
+ * Clears error status.
+ * Application calls this function to clear error status.
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * pErrStat Pointer to errot status bit-field mask.
+ *
+ * return: none
+ */
+void PRUI2S_clearErrStat(
+ PRUI2S_Handle handle,
+ uint8_t errMask
+)
+{
+ PRUI2S_Config *pCfg;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ uint8_t regVal;
+
+ /* Get pointers */
+ pCfg = (PRUI2S_Config *)handle;
+ pSwipAttrs = pCfg->attrs;
+
+ regVal = HW_RD_REG8(pSwipAttrs->baseAddr + FW_REG_ERR_STAT);
+ regVal &= ~errMask;
+ HW_WR_REG8(pSwipAttrs->baseAddr + FW_REG_ERR_STAT, regVal);
+}
+
+/*
+ * Disables PRUI2S interrupt
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * intrType Type of interrupt to disable
+ *
+ * return: status code
+ */
+int32_t PRUI2S_disableInt(
+ PRUI2S_Handle handle,
+ uint8_t intrType
+)
+{
+ PRUI2S_Config *pCfg;
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ uint8_t icssIntcSysEvt;
+ int32_t status;
+ int32_t retStatus = PRUI2S_DRV_SOK;
+
+ /* Get pointers */
+ pCfg = (PRUI2S_Config *)handle;
+ pObj = pCfg->object;
+ pSwipAttrs = pCfg->attrs;
+
+ /* Get system event for interrupt type */
+ if (intrType == INTR_TYPE_I2S_TX)
+ {
+ icssIntcSysEvt = pSwipAttrs->i2sTxIcssIntcSysEvt;
+ }
+ else if (intrType == INTR_TYPE_I2S_RX)
+ {
+ icssIntcSysEvt = pSwipAttrs->i2sRxIcssIntcSysEvt;
+ }
+ else if (intrType == INTR_TYPE_I2S_ERR)
+ {
+ icssIntcSysEvt = pSwipAttrs->i2sErrIcssIntcSysEvt;
+ }
+ else
+ {
+ retStatus = PRUI2S_DRV_SERR_INV_PRMS;
+ }
+
+ if (retStatus == PRUI2S_DRV_SOK)
+ {
+ status = PRUICSS_disableEvent(pObj->pruIcssHandle, icssIntcSysEvt);
+ if (status != SystemP_SUCCESS) {
+ retStatus = PRUI2S_DRV_SERR_CLR_INT;
+ }
+ }
+
+ return retStatus;
+}
+
+/*
+ * Enables PRUI2S interrupt
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * intrType Type of interrupt to disable
+ *
+ * return: status code
+ */
+int32_t PRUI2S_enableInt(
+ PRUI2S_Handle handle,
+ uint8_t intrType
+)
+{
+ PRUI2S_Config *pCfg;
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ uint8_t icssIntcSysEvt;
+ int32_t status;
+ int32_t retStatus = PRUI2S_DRV_SOK;
+
+ /* Get pointers */
+ pCfg = (PRUI2S_Config *)handle;
+ pObj = pCfg->object;
+ pSwipAttrs = pCfg->attrs;
+
+ /* Get system event for interrupt type */
+ if (intrType == INTR_TYPE_I2S_TX)
+ {
+ icssIntcSysEvt = pSwipAttrs->i2sTxIcssIntcSysEvt;
+ }
+ else if (intrType == INTR_TYPE_I2S_RX)
+ {
+ icssIntcSysEvt = pSwipAttrs->i2sRxIcssIntcSysEvt;
+ }
+ else if (intrType == INTR_TYPE_I2S_ERR)
+ {
+ icssIntcSysEvt = pSwipAttrs->i2sErrIcssIntcSysEvt;
+ }
+ else
+ {
+ retStatus = PRUI2S_DRV_SERR_INV_PRMS;
+ }
+
+ if (retStatus == PRUI2S_DRV_SOK)
+ {
+ status = PRUICSS_enableEvent(pObj->pruIcssHandle, icssIntcSysEvt);
+ if (status != SystemP_SUCCESS) {
+ retStatus = PRUI2S_DRV_SERR_CLR_INT;
+ }
+ }
+
+ return retStatus;
+}
+
+/*
+ * Clears PRUI2S interrupt
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * intrType Type of interrupt to disable
+ *
+ * return: status code
+ */
+int32_t PRUI2S_clearInt(
+ PRUI2S_Handle handle,
+ uint8_t intrType
+)
+{
+ PRUI2S_Config *pCfg;
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ uint8_t icssIntcSysEvt;
+ int32_t status;
+ int32_t retStatus = PRUI2S_DRV_SOK;
+
+ /* Get pointers */
+ pCfg = (PRUI2S_Config *)handle;
+ pObj = pCfg->object;
+ pSwipAttrs = pCfg->attrs;
+
+ /* Get system event for interrupt type */
+ if (intrType == INTR_TYPE_I2S_TX)
+ {
+ icssIntcSysEvt = pSwipAttrs->i2sTxIcssIntcSysEvt;
+ }
+ else if (intrType == INTR_TYPE_I2S_RX)
+ {
+ icssIntcSysEvt = pSwipAttrs->i2sRxIcssIntcSysEvt;
+ }
+ else if (intrType == INTR_TYPE_I2S_ERR)
+ {
+ icssIntcSysEvt = pSwipAttrs->i2sErrIcssIntcSysEvt;
+ }
+ else
+ {
+ retStatus = PRUI2S_DRV_SERR_INV_PRMS;
+ }
+
+ if (retStatus == PRUI2S_DRV_SOK)
+ {
+ status = PRUICSS_clearEvent(pObj->pruIcssHandle, icssIntcSysEvt);
+ if (status != SystemP_SUCCESS) {
+ retStatus = PRUI2S_DRV_SERR_CLR_INT;
+ }
+ }
+
+ return retStatus;
+}
+
+/* Extracts information in PRU FW pseudo-registers, update SW IP using extracted info.
+ Info is contained in PRU FW DMEM image. */
+static int32_t PRUI2S_getPruFwImageInfo(
+ PRUI2S_PruFwImageInfo *pPruFwImageInfo,
+ PRUI2S_SwipAttrs *pSwipAttrs
+)
+{
+ const uint8_t *pPruDmemImg = pPruFwImageInfo->pPruDmemImg;
+ uint8_t temp8b;
+
+ /* Update number of Tx I2S */
+ temp8b = pPruDmemImg[FW_REG_NUM_TX_I2S_OFFSET];
+ pSwipAttrs->numTxI2s = temp8b;
+
+ /* Update number of Rx I2S */
+ temp8b = pPruDmemImg[FW_REG_NUM_RX_I2S_OFFSET];
+ pSwipAttrs->numRxI2s = temp8b;
+
+ /* Update sampling frequency */
+ temp8b = pPruDmemImg[FW_REG_SAMP_FREQ_OFFSET];
+ pSwipAttrs->sampFreq = temp8b;
+
+ /* Update number if bits per I2S slot */
+ temp8b = pPruDmemImg[FW_REG_BITS_PER_SLOT_OFFSET];
+ pSwipAttrs->bitsPerSlot = temp8b;
+
+ /* Update I2S Tx ICSS INTC system event number */
+ temp8b = pPruDmemImg[FW_REG_I2S_TX_ICSS_INTC_SYS_EVT_OFFSET];
+ pSwipAttrs->i2sTxIcssIntcSysEvt = temp8b;
+
+ /* Update I2S Rx ICSS INTC system event number */
+ temp8b = pPruDmemImg[FW_REG_I2S_RX_ICSS_INTC_SYS_EVT_OFFSET];
+ pSwipAttrs->i2sRxIcssIntcSysEvt = temp8b;
+
+ /* Update I2S error ICSS INTC system event number */
+ temp8b = pPruDmemImg[FW_REG_I2S_ERR_ICSS_INTC_SYS_EVT_OFFSET];
+ pSwipAttrs->i2sErrIcssIntcSysEvt = temp8b;
+
+ /*
+ * NOTE: GPIO pin configuration is now handled by SysConfig.
+ * Pin numbers are defined in firmware but GPIO/pinmux is configured via SysConfig.
+ * No need to store or validate pin numbers in driver.
+ */
+
+ return SystemP_SUCCESS;
+}
+
+/* Checks SW IP parameters */
+static int32_t PRUI2S_checkSwipParams(
+ PRUI2S_SwipAttrs *pSwipAttrs
+)
+{
+ const PRUICSS_HwAttrs *pPruIcssHwAttrs;
+ uint32_t icssHwInstId;
+ int32_t status = SystemP_SUCCESS;
+
+ pPruIcssHwAttrs = PRUICSS_getAttrs(pSwipAttrs->icssInstId);
+ icssHwInstId = pPruIcssHwAttrs->instance;
+
+ /* Note: baseAddr is calculated in PRUI2S_open(), so skip check here during init */
+ /* Skipping baseAddr check during PRUI2S_init() */
+
+ /* Check PRU core ID */
+ if ((status == SystemP_SUCCESS) &&
+ ((pSwipAttrs->pruInstId != PRUICSS_PRU0) && (pSwipAttrs->pruInstId != PRUICSS_PRU1)))
+ {
+ status = SystemP_FAILURE;
+ }
+
+ /* Check number of I2S instance */
+ if ((status == SystemP_SUCCESS) &&
+ ((pSwipAttrs->numTxI2s == 0) && (pSwipAttrs->numRxI2s == 0)))
+ {
+ status = SystemP_FAILURE;
+ }
+ if ((status == SystemP_SUCCESS) &&
+ ((pSwipAttrs->numTxI2s != 0) && (pSwipAttrs->numRxI2s != 0)) &&
+ (pSwipAttrs->numTxI2s != pSwipAttrs->numRxI2s))
+ {
+ status = SystemP_FAILURE;
+ }
+
+ /* Check bits per I2S slot */
+ if ((status == SystemP_SUCCESS) &&
+ ((pSwipAttrs->bitsPerSlot != PRUI2S_BITS_PER_SLOT_16) &&
+ (pSwipAttrs->bitsPerSlot != PRUI2S_BITS_PER_SLOT_32)))
+ {
+ status = SystemP_FAILURE;
+ }
+
+ /*
+ Check Host interrupt numbers.
+ Note: Host interrupt validation is now device/instance-agnostic.
+ Application provides interrupt numbers via SysConfig, which handles validation.
+ */
+ /* Host interrupt validation is now delegated to SysConfig */
+ (void)icssHwInstId; /* Mark icssHwInstId as used to avoid compiler warnings */
+
+ /* Check ICSS system event numbers */
+ if ((status == SystemP_SUCCESS) &&
+ ((pSwipAttrs->i2sTxIcssIntcSysEvt < PRU_ARM_EVENT00) ||
+ (pSwipAttrs->i2sTxIcssIntcSysEvt > PRU_ARM_EVENT15)))
+ {
+ status = SystemP_FAILURE;
+ }
+ if ((status == SystemP_SUCCESS) &&
+ ((pSwipAttrs->i2sRxIcssIntcSysEvt < PRU_ARM_EVENT00) ||
+ (pSwipAttrs->i2sRxIcssIntcSysEvt > PRU_ARM_EVENT15)))
+ {
+ status = SystemP_FAILURE;
+ }
+ if ((status == SystemP_SUCCESS) &&
+ ((pSwipAttrs->i2sErrIcssIntcSysEvt < PRU_ARM_EVENT00) ||
+ (pSwipAttrs->i2sErrIcssIntcSysEvt > PRU_ARM_EVENT15)))
+ {
+ status = SystemP_FAILURE;
+ }
+
+ /* NOTE: GPIO pin validation is no longer needed.
+ * GPIO/pinmux is now configured via SysConfig, which handles pin validation. */
+
+ return status;
+}
+
+/* Checks parameters used for PRUI2S_open() function */
+static int32_t PRUI2S_checkOpenParams(
+ PRUI2S_SwipAttrs *pSwipAttrs,
+ PRUI2S_Params *pPrms
+)
+{
+ int32_t status = SystemP_SUCCESS;
+
+ /* Check Tx I2S parameters */
+ if (pSwipAttrs->numTxI2s > 0)
+ {
+ /* Check Tx interrupt priority */
+ if (pPrms->i2sTxIntrPri > MAX_VIM_INTR_PRI_VAL)
+ {
+ status = SystemP_FAILURE;
+ }
+
+ /* Check Tx interrupt callback function */
+ if ((status == SystemP_SUCCESS) && (pPrms->i2sTxCallbackFxn == NULL))
+ {
+ status = SystemP_FAILURE;
+ }
+
+ /* Check Tx ping/pong buffer base address.
+ Tx ping/pong buffer is expected to be in ICSS SHMEM.
+ Note: Absolute buffer address validation is delegated to application
+ during PRUI2S_open() when full PRUICSS handle context is available. */
+ if ((status == SystemP_SUCCESS) && (pPrms->txPingPongBaseAddr == 0))
+ {
+ status = SystemP_FAILURE;
+ }
+ }
+
+ /* Check Rx I2S parameters */
+ if ((status == SystemP_SUCCESS) && (pSwipAttrs->numRxI2s > 0))
+ {
+ /* Check Rx interrupt priority */
+ if (pPrms->i2sRxIntrPri > MAX_VIM_INTR_PRI_VAL)
+ {
+ status = SystemP_FAILURE;
+ }
+
+ /* Check Rx interrupt callback function */
+ if ((status == SystemP_SUCCESS) && (pPrms->i2sRxCallbackFxn == NULL))
+ {
+ status = SystemP_FAILURE;
+ }
+
+ /* Check Rx ping/pong buffer base address */
+ if ((status == SystemP_SUCCESS) && (pPrms->rxPingPongBaseAddr == 0))
+ {
+ status = SystemP_FAILURE;
+ }
+ }
+
+ /* Check ping/pong buffer size */
+ if ((status == SystemP_SUCCESS) &&
+ (pPrms->pingPongBufSz == 0))
+ {
+ status = SystemP_FAILURE;
+ }
+
+ /* Check I2S error parameters */
+ if ((status == SystemP_SUCCESS) && (pPrms->i2sErrCallbackFxn != NULL))
+ {
+ /* Check I2S error interrupt priority */
+ if (pPrms->i2sErrIntrPri > MAX_VIM_INTR_PRI_VAL)
+ {
+ status = SystemP_FAILURE;
+ }
+ }
+
+ return status;
+}
+
+/* Initializes PRU for PRU I2S */
+static int32_t PRUI2S_initPru(
+ PRUI2S_Config *pCfg
+)
+{
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ PRUI2S_Params *pPrms;
+ uint8_t pruInstId;
+ PRUICSS_Handle pruIcssHandle;
+ int32_t size;
+ int32_t status = SystemP_SUCCESS;
+
+
+ /* Get pointers */
+ pObj = pCfg->object;
+ pSwipAttrs = pCfg->attrs;
+ pPrms = &pCfg->object->prms;
+
+
+ if (pPrms == NULL)
+ {
+ return PRUI2S_DRV_SERR_INV_PRMS;
+ }
+
+ pruInstId = pSwipAttrs->pruInstId;
+
+ /* Use PRUICSS handle already set in PRUI2S_open() */
+ pruIcssHandle = pObj->pruIcssHandle;
+
+ if (pruIcssHandle == NULL)
+ {
+ return PRUI2S_DRV_SERR_INV_PRMS;
+ }
+
+ /* Disable PRU core */
+ status = PRUICSS_disableCore(pruIcssHandle, pruInstId);
+ if (status != SystemP_SUCCESS)
+ {
+ return PRUI2S_DRV_SERR_INIT;
+ }
+
+ /* Set ICSS pin mux */
+ status = PRUICSS_setSaMuxMode(pruIcssHandle, PRUICSS_G_MUX_EN);
+ if (status != SystemP_SUCCESS)
+ {
+ return PRUI2S_DRV_SERR_INIT;
+ }
+
+ /* Reset PRU core */
+ status = PRUICSS_resetCore(pruIcssHandle, pruInstId);
+ if (status != SystemP_SUCCESS)
+ {
+ return PRUI2S_DRV_SERR_INIT;
+ }
+
+ /* Initialize DATARAM */
+ size = PRUICSS_initMemory(pruIcssHandle, PRUICSS_DATARAM(pruInstId));
+ if (size == 0)
+ {
+ return PRUI2S_DRV_SERR_INIT;
+ }
+
+ /* Initialize IRAM */
+ size = PRUICSS_initMemory(pruIcssHandle, PRUICSS_IRAM_PRU(pruInstId));
+ if (size == 0)
+ {
+ return PRUI2S_DRV_SERR_INIT;
+ }
+
+ /* Firmware loading is handled by application in prui2s_pruicss_load_run_fw()
+ * Driver assumes firmware is already loaded when PRUI2S_initPru() is called
+ * This avoids duplicate firmware loads and simplifies driver initialization
+ *
+ * PRU core enable is also handled by application in prui2s_pruicss_load_run_fw()
+ * Driver does not enable cores here to avoid conflicts with application
+ */
+
+ return SystemP_SUCCESS;
+}
+
+/* Application calls PRUICSS_intcInit() directly before PRUI2S_open().
+ * This matches Motor Control SDK pattern (HDSL, EnDAT3, BiSS-C).
+ */
+
+/* Initializes PRU I2S FW */
+static int32_t PRUI2S_initFw(
+ PRUI2S_Config *pCfg
+)
+{
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ uint32_t tmpRxPpBufAddr;
+
+ /* Get pointers */
+ pObj = pCfg->object;
+ pSwipAttrs = pCfg->attrs;
+
+ if (pSwipAttrs->numTxI2s > 0)
+ {
+ /* Write Tx ping/pong buffer address */
+ HW_WR_REG32(pSwipAttrs->baseAddr + FW_REG_TX_PING_PONG_BUF_ADDR, pObj->prms.txPingPongBaseAddr);
+ }
+
+ if (pSwipAttrs->numRxI2s > 0)
+ {
+ /* Rx buffer address passed from application is expected to be the target address
+ (either ICSS local address or absolute system address).
+ This is now application/SysConfig responsibility to provide correctly.
+ Firmware will use this address as-is. */
+ tmpRxPpBufAddr = pObj->prms.rxPingPongBaseAddr;
+
+ /* Write Rx ping/pong buffer address */
+ HW_WR_REG32(pSwipAttrs->baseAddr + FW_REG_RX_PING_PONG_BUF_ADDR, tmpRxPpBufAddr);
+ }
+
+ /* Write ping/pong buffer size */
+ HW_WR_REG16(pSwipAttrs->baseAddr + FW_REG_PING_PONG_BUF_SZ, pObj->prms.pingPongBufSz);
+
+ /* TBD: other FW reg init */
+
+ return SystemP_SUCCESS;
+}
+
+/* Initializes PRU I2S ping/pong buffers */
+static int32_t PRUI2S_initPpBufs(
+ PRUI2S_Config *pCfg
+)
+{
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ const PRUICSS_HwAttrs *pPruIcssHwAttrs;
+ int32_t status = SystemP_SUCCESS;
+
+
+ /* Get pointers */
+ pObj = pCfg->object;
+ pSwipAttrs = pCfg->attrs;
+
+
+ if (pSwipAttrs->numTxI2s > 0)
+ {
+ /* Get PRUICSS hardware attributes from the handle */
+ pPruIcssHwAttrs = (PRUICSS_HwAttrs *)(pObj->pruIcssHandle->hwAttrs);
+
+ if (pPruIcssHwAttrs != NULL)
+ {
+ uint32_t pruDramBase = 0;
+
+
+ /* Get PRU-specific DRAM base address from hardware attributes - device/instance agnostic */
+ /* The PRUICSS handle provides the actual DRAM mapping for any PRU on any device */
+ if (pSwipAttrs->pruInstId == PRUICSS_PRU0)
+ {
+ pruDramBase = (uint32_t)pPruIcssHwAttrs->pru0DramBase;
+ }
+ else if (pSwipAttrs->pruInstId == PRUICSS_PRU1)
+ {
+ pruDramBase = (uint32_t)pPruIcssHwAttrs->pru1DramBase;
+ }
+ else
+ {
+ status = SystemP_FAILURE;
+ }
+
+ if ((status == SystemP_SUCCESS) && (pruDramBase != 0))
+ {
+ /* Calculate Tx buffer address using PRU DRAM base + application offset */
+ pObj->txPingPongBuf = (void *)(pruDramBase + pObj->prms.txPingPongBaseAddr);
+ }
+ else
+ {
+ status = SystemP_FAILURE;
+ }
+ }
+ else
+ {
+ status = SystemP_FAILURE;
+ }
+
+ if (status == SystemP_SUCCESS)
+ {
+ memset((uint8_t *)pObj->txPingPongBuf, 0, pObj->prms.pingPongBufSz);
+ }
+ }
+
+ if ((status == SystemP_SUCCESS) && (pSwipAttrs->numRxI2s > 0))
+ {
+
+ /* Rx buffer address is provided by application as a complete target address (not an offset) */
+ /* This allows application to specify buffers in OCRAM, DDR, or other memory locations */
+ if (pObj->prms.rxPingPongBaseAddr != 0)
+ {
+ pObj->rxPingPongBuf = (void *)pObj->prms.rxPingPongBaseAddr;
+ }
+ else
+ {
+ status = SystemP_FAILURE;
+ }
+
+ if (status == SystemP_SUCCESS)
+ {
+ memset((uint8_t *)pObj->rxPingPongBuf, 0, pObj->prms.pingPongBufSz);
+ }
+ }
+
+ return status;
+}
+
+/* De-initializes PRU for PRU I2S */
+static int32_t PRUI2S_deinitPru(
+ PRUI2S_Config *pCfg
+)
+{
+ PRUI2S_Object *pObj;
+ PRUI2S_SwipAttrs *pSwipAttrs;
+ PRUICSS_Handle pruIcssHandle;
+ uint8_t pruInstId;
+ int32_t size;
+ int32_t status = SystemP_SUCCESS;
+
+ /* Get pointers */
+ pObj = pCfg->object;
+ pSwipAttrs = pCfg->attrs;
+
+ pruIcssHandle = pObj->pruIcssHandle;
+ pruInstId = pSwipAttrs->pruInstId;
+
+ /* Early return if handle is NULL (init failed before handle assignment) */
+ if (pruIcssHandle == NULL)
+ {
+ return SystemP_SUCCESS;
+ }
+
+ /* Disable PRU core */
+ status = PRUICSS_disableCore(pruIcssHandle, pruInstId);
+
+ if (status == SystemP_SUCCESS)
+ {
+ /* Reset PRU core */
+ status = PRUICSS_resetCore(pruIcssHandle, pruInstId);
+ }
+
+ if (status == SystemP_SUCCESS)
+ {
+ /* Initialize DMEM to 0 */
+ size = PRUICSS_initMemory(pruIcssHandle, PRUICSS_DATARAM(pruInstId));
+ if (size == 0)
+ {
+ status = SystemP_FAILURE;
+ }
+ }
+
+ if (status == SystemP_SUCCESS)
+ {
+ /* Initialize IMEM to 0 */
+ size = PRUICSS_initMemory(pruIcssHandle, PRUICSS_IRAM_PRU(pruInstId));
+ if (size == 0)
+ {
+ status = SystemP_FAILURE;
+ }
+ else
+ {
+ pObj->pruIcssHandle = NULL;
+ }
+ }
+
+ return status;
+}
+
+int32_t PRUICSS_enableEvent(PRUICSS_Handle handle, uint32_t eventnum)
+{
+ uintptr_t baseaddr;
+ PRUICSS_HwAttrs const *hwAttrs;
+ int32_t retVal = SystemP_FAILURE;
+
+ if (handle != NULL)
+ {
+ hwAttrs = (PRUICSS_HwAttrs const *)handle->hwAttrs;
+ baseaddr = hwAttrs->intcRegBase;
+
+ HW_WR_FIELD32((baseaddr + CSL_ICSS_M_PR1_ICSS_INTC_SLV_ENABLE_SET_INDEX_REG), CSL_ICSS_M_PR1_ICSS_INTC_SLV_ENABLE_SET_INDEX_REG_ENABLE_SET_INDEX, eventnum);
+ retVal = SystemP_SUCCESS;
+ }
+ return retVal;
+}
+
+int32_t PRUICSS_disableEvent(PRUICSS_Handle handle, uint32_t eventnum)
+{
+ uintptr_t baseaddr;
+ PRUICSS_HwAttrs const *hwAttrs;
+ int32_t retVal = SystemP_FAILURE;
+
+ if (handle != NULL)
+ {
+ hwAttrs = (PRUICSS_HwAttrs const *)handle->hwAttrs;
+ baseaddr = hwAttrs->intcRegBase;
+
+ HW_WR_FIELD32((baseaddr + CSL_ICSS_M_PR1_ICSS_INTC_SLV_ENABLE_CLR_INDEX_REG), CSL_ICSS_M_PR1_ICSS_INTC_SLV_ENABLE_CLR_INDEX_REG_ENABLE_CLR_INDEX, eventnum);
+ retVal = SystemP_SUCCESS;
+ }
+ return retVal;
+}
+
+/* Application calls PRUICSS_intcInit() directly for initialization.
+ * Runtime control uses PRUICSS_enableEvent() and PRUICSS_disableEvent() below.
+ */
diff --git a/examples/pru_i2s/firmware/I2S/fw_regs.asm b/examples/pru_i2s/firmware/I2S/fw_regs.asm
new file mode 100644
index 000000000..d2b3837bd
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/fw_regs.asm
@@ -0,0 +1,113 @@
+;
+; Copyright (c) 2025, Texas Instruments Incorporated
+; All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+;
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+;
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in the
+; documentation and/or other materials provided with the distribution.
+;
+; * Neither the name of Texas Instruments Incorporated nor the names of
+; its contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+; EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;
+
+ .cdecls C,NOLIST
+%{
+ #include "icss_pru_i2s_fw.h"
+%}
+
+ ; PRU I2S Firmware Registers
+ .sect ".fwRegs"
+ .retain ".fwRegs"
+ .retainrefs ".fwRegs"
+ .space ICSS_PRUI2S_FW_REG_BASE
+ .if $isdefed("NUMBER_OF_TX_2")
+ .byte 2 ; NUM_TX_I2S
+ .endif
+ .if $isdefed("NUMBER_OF_TX_3")
+ .byte 3 ; NUM_TX_I2S
+ .endif
+ .if !$isdefed("NUMBER_OF_TX_2")
+ .if !$isdefed("NUMBER_OF_TX_3")
+ .byte 0 ; NUM_TX_I2S
+ .endif
+ .endif
+ .if $isdefed("I2S_RX")
+ .byte 2 ; NUM_RX_I2S
+ .else
+ .byte 0 ; NUM_RX_I2S
+ .endif
+ .byte 48 ; SAMP_FREQ
+ .if $isdefed("SOC_AM64X")
+ .byte 16 ; BITS_PER_SLOT
+ .else
+ .byte 32 ; BITS_PER_SLOT
+ .endif
+ .if $isdefed("PRU0")
+ .word 0x10000 ; TX_PING_PONG_BUF_ADDR
+ .else
+ .word 0x10200 ; TX_PING_PONG_BUF_ADDR
+ .endif
+ .if $isdefed("NUMBER_OF_TX_3")
+ .short 264 ; PING_PONG_BUF_SZ
+ .else
+ .short 256 ; PING_PONG_BUF_SZ
+ .endif
+ .if $isdefed("PRU0")
+ .byte 18 ; I2S_TX_ICSS_INTC_SYS_EVT (Event 18=16+2)
+ .byte 19 ; I2S_RX_ICSS_INTC_SYS_EVT (Event 19=16+3)
+ .byte 20 ; I2S_ERR_ICSS_INTC_SYS_EVT (Event 20=16+4)
+ .else
+ .byte 21 ; I2S_TX_ICSS_INTC_SYS_EVT (Event 21=16+5)
+ .byte 22 ; I2S_RX_ICSS_INTC_SYS_EVT (Event 22=16+6)
+ .byte 23 ; I2S_ERR_ICSS_INTC_SYS_EVT (Event 23=16+7)
+ .endif
+
+ .if $isdefed("PRU0")
+ .byte 6 ; PIN_NUM_BCLK
+ .byte 1 ; PIN_NUM_FSYNC
+ .byte 2 ; PIN_NUM_TX0/RESERVED in case of RX Only
+ .byte 3 ; PIN_NUM_TX1/RESERVED in case of RX Only
+ .byte 5 ; PIN_NUM_TX2/RESERVED in case of RX Only/2Tx Only
+ .byte 0 ; PIN_NUM_RX0
+ .byte 4 ; PIN_NUM_RX1
+ .else
+ .byte 0 ; PIN_NUM_BCLK
+ .byte 1 ; PIN_NUM_FSYNC
+ .byte 4 ; PIN_NUM_TX0/RESERVED in case of RX Only
+ .byte 5 ; PIN_NUM_TX1/RESERVED in case of RX Only
+ .byte 6 ; PIN_NUM_TX2/RESERVED in case of RX Only/2Tx Only
+ .byte 2 ; PIN_NUM_RX0
+ .byte 3 ; PIN_NUM_RX1
+ .endif
+
+ .if $isdefed("PRU0")
+ .word 0x10100 ; RX_PING_PONG_BUF_ADDR
+ .else
+ .word 0x10300 ; RX_PING_PONG_BUF_ADDR
+ .endif
+ .byte 0 ; TX_PING_PONG_SEL
+ .byte 0 ; RX_PING_PONG_SEL
+ .byte 2 ; TX_PING_PONG_STAT
+ .byte 1 ; RX_PING_PONG_STAT
+ .byte 0 ; ERR_STAT
+
diff --git a/examples/pru_i2s/firmware/I2S/icss_pru_i2s_fw.h b/examples/pru_i2s/firmware/I2S/icss_pru_i2s_fw.h
new file mode 100644
index 000000000..4d172dcb2
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/icss_pru_i2s_fw.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ICSS_pru_i2s_FW_H_
+#define _ICSS_pru_i2s_FW_H_
+
+/*
+ Firmware registers
+*/
+
+/* FW register base address */
+#define ICSS_PRUI2S_FW_REG_BASE ( 0x0000 )
+
+/* FW register sizes (in bytes) */
+#define FW_REG_NUM_TX_I2S_SZ ( 1 )
+#define FW_REG_NUM_RX_I2S_SZ ( 1 )
+#define FW_REG_SAMP_FREQ_SZ ( 1 )
+#define FW_REG_BITS_PER_SLOT_SZ ( 1 )
+#define FW_REG_TX_PING_PONG_BUF_ADDR_SZ ( 4 )
+#define FW_REG_PING_PONG_BUF_SZ_SZ ( 2 )
+#define FW_REG_I2S_ICSS_INTC_SYS_EVT_SZ ( 1 )
+#define FW_REG_I2S_ERR_ICSS_INTC_SYS_EVT_SZ ( 1 )
+#define FW_REG_I2S_PIN_NUM_SZ ( 1 )
+
+/* FW register offsets from base (in bytes) */
+#define FW_REG_NUM_TX_I2S_OFFSET ( 0x00 )
+#define FW_REG_NUM_RX_I2S_OFFSET ( 0x01 )
+#define FW_REG_SAMP_FREQ_OFFSET ( 0x02 )
+#define FW_REG_BITS_PER_SLOT_OFFSET ( 0x03 )
+#define FW_REG_TX_PING_PONG_BUF_ADDR_OFFSET ( 0x04 )
+#define FW_REG_PING_PONG_BUF_SZ_OFFSET ( 0x08 )
+#define FW_REG_I2S_TX_ICSS_INTC_SYS_EVT_OFFSET ( 0x0A )
+#define FW_REG_I2S_RX_ICSS_INTC_SYS_EVT_OFFSET ( 0x0B )
+#define FW_REG_I2S_ERR_ICSS_INTC_SYS_EVT_OFFSET ( 0x0C )
+#define FW_REG_I2S_PIN_NUM_BCLK_OFFSET ( 0x0D )
+#define FW_REG_I2S_PIN_NUM_FSYNC_OFFSET ( 0x0E )
+#define FW_REG_I2S_PIN_NUM_TX0_OFFSET ( 0x0F )
+#define FW_REG_I2S_PIN_NUM_TX1_OFFSET ( 0x10 )
+#define FW_REG_I2S_PIN_NUM_TX2_OFFSET ( 0x11 )
+#define FW_REG_I2S_PIN_NUM_RX0_OFFSET ( 0x12 )
+#define FW_REG_I2S_PIN_NUM_RX1_OFFSET ( 0x13 )
+#define FW_REG_RX_PING_PONG_BUF_ADDR_OFFSET ( 0x14 )
+#define FW_REG_TX_PING_PONG_SEL_OFFSET ( 0x18 )
+#define FW_REG_RX_PING_PONG_SEL_OFFSET ( 0x19 )
+#define FW_REG_TX_PING_PONG_STAT_OFFSET ( 0x1A )
+#define FW_REG_RX_PING_PONG_STAT_OFFSET ( 0x1B )
+#define FW_REG_ERR_STAT_OFFSET ( 0x1C )
+
+/* FW register addresses */
+#define FW_REG_NUM_TX_I2S ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_NUM_TX_I2S_OFFSET )
+#define FW_REG_NUM_RX_I2S ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_NUM_RX_I2S_OFFSET )
+#define FW_REG_SAMP_FREQ ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_SAMP_FREQ_OFFSET )
+#define FW_REG_BITS_PER_SLOT ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_BITS_PER_SLOT_OFFSET )
+#define FW_REG_TX_PING_PONG_BUF_ADDR ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_TX_PING_PONG_BUF_ADDR_OFFSET )
+#define FW_REG_PING_PONG_BUF_SZ ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_PING_PONG_BUF_SZ_OFFSET )
+#define FW_REG_I2S_TX_ICSS_INTC_SYS_EVT ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_TX_ICSS_INTC_SYS_EVT_OFFSET )
+#define FW_REG_I2S_RX_ICSS_INTC_SYS_EVT ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_RX_ICSS_INTC_SYS_EVT_OFFSET )
+#define FW_REG_I2S_ERR_ICSS_INTC_SYS_EVT ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_ERR_ICSS_INTC_SYS_EVT_OFFSET )
+#define FW_REG_I2S_PIN_NUM_BCLK ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_PIN_NUM_BCLK_OFFSET )
+#define FW_REG_I2S_PIN_NUM_FSYNC ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_PIN_NUM_FSYNC_OFFSET )
+#define FW_REG_I2S_PIN_NUM_TX0 ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_PIN_NUM_TX0_OFFSET )
+#define FW_REG_I2S_PIN_NUM_TX1 ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_PIN_NUM_TX1_OFFSET )
+#define FW_REG_I2S_PIN_NUM_TX2 ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_PIN_NUM_TX2_OFFSET )
+#define FW_REG_I2S_PIN_NUM_RX0 ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_PIN_NUM_RX0_OFFSET )
+#define FW_REG_I2S_PIN_NUM_RX1 ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_PIN_NUM_RX1_OFFSET )
+#define FW_REG_RX_PING_PONG_BUF_ADDR ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_RX_PING_PONG_BUF_ADDR_OFFSET )
+#define FW_REG_TX_PING_PONG_SEL ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_TX_PING_PONG_SEL_OFFSET )
+#define FW_REG_RX_PING_PONG_SEL ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_RX_PING_PONG_SEL_OFFSET )
+#define FW_REG_TX_PING_PONG_STAT ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_TX_PING_PONG_STAT_OFFSET )
+#define FW_REG_RX_PING_PONG_STAT ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_RX_PING_PONG_STAT_OFFSET )
+#define FW_REG_ERR_STAT ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_ERR_STAT_OFFSET )
+
+/*
+ Firmware register bit fields
+*/
+
+/* NUM_TX_I2S */
+#define BF_NUM_TX_I2S_MASK ( 0x3 )
+#define NUM_TX_I2S_BF_NUM_TX_I2S_SHIFT ( 0 )
+#define NUM_TX_I2S_BF_NUM_TX_I2S_MASK ( BF_NUM_TX_I2S_MASK << NUM_TX_I2S_BF_NUM_TX_I2S_SHIFT )
+
+/* NUM_RX_I2S */
+#define BF_NUM_RX_I2S_MASK ( 0x3 )
+#define NUM_TX_I2S_BF_NUM_RX_I2S_SHIFT ( 0 )
+#define NUM_TX_I2S_BF_NUM_RX_I2S_MASK ( BF_NUM_RX_I2S_MASK << NUM_TX_I2S_BF_NUM_RX_I2S_SHIFT )
+
+/* FW_REG_SAMP_FREQ */
+#define BF_SAMP_FREQ_MASK ( 0xFF )
+#define SAMP_FREQ_BF_SAMP_FREQ_SHIFT ( 0 )
+#define SAMP_FREQ_BF_SAMP_FREQ_MASK ( BF_SAMP_FREQ_MASK << SAMP_FREQ_BF_SAMP_FREQ_SHIFT )
+
+/* FW_REG_BITS_PER_SLOT */
+#define BF_BITS_PER_SLOT_MASK ( 0x1F )
+#define BITS_PER_SLOT_BF_BITS_PER_SLOT_SHIFT ( 0 )
+#define BITS_PER_SLOT_BF_BITS_PER_SLOT_MASK ( BF_BITS_PER_SLOT_MASK << BITS_PER_SLOT_BF_BITS_PER_SLOT_SHIFT )
+
+/* FW_REG_TX_PING_PONG_BUF_ADDR */
+#define BF_TX_BUF_PING_PONG_BUF_ADDR_MASK ( 0xFFFFFFFF )
+#define TX_BUF_PING_PONG_BUF_ADDR_BF_TX_BUF_PING_PONG_BUF_ADDR_SHIFT \
+ ( 0 )
+#define TX_BUF_PING_PONG_BUF_ADDR_BF_TX_BUF_PING_PONG_BUF_ADDR_MASK \
+ ( BF_TX_BUF_PING_PONG_BUF_ADDR_MASK << TX_BUF_PING_PONG_BUF_ADDR_BF_TX_BUF_PING_PONG_BUF_ADDR_SHIFT )
+
+/* FW_REG_PING_PONG_BUF_SZ */
+#define BF_PING_PONG_BUF_SZ_MASK ( 0xFFFF )
+#define TX_PING_PONG_BUF_SZ_BF_PING_PONG_BUF_SZ_SHIFT \
+ ( 0 )
+#define TX_PING_PONG_BUF_SZ_BF_PING_PONG_BUF_SZ_MASK \
+ ( BF_PING_PONG_BUF_SZ_MASK << TX_PING_PONG_BUF_SZ_BF_PING_PONG_BUF_SZ_SHIFT )
+
+/* FW_REG_I2S_ICSS_INTC_SYS_EVT */
+#define BF_I2S_ICSS_INTC_SYS_EVT_MASK ( 0xFF )
+#define I2S_ICSS_INTC_SYS_EVT_BF_I2S_ICSS_INTC_SYS_EVT_SHIFT \
+ ( 0 )
+#define I2S_ICSS_INTC_SYS_EVT_BF_I2S_ICSS_INTC_SYS_EVT_MASK \
+ ( BF_I2S_ICSS_INTC_SYS_EVT_MASK << I2S_ICSS_INTC_SYS_EVT_BF_I2S_ICSS_INTC_SYS_EVT_SHIFT )
+
+/* FW_REG_I2S_ERR_ICSS_INTC_SYS_EVT */
+#define BF_I2S_ERR_ICSS_INTC_SYS_EVT_MASK ( 0xFF )
+#define I2S_ERR_ICSS_INTC_SYS_EVT_BF_I2S_ERR_ICSS_INTC_SYS_EVT_SHIFT \
+ ( 0 )
+#define I2S_ERR_ICSS_INTC_SYS_EVT_BF_I2S_ERR_ICSS_INTC_SYS_EVT_MASK \
+ ( BF_I2S_ERR_ICSS_INTC_SYS_EVT_MASK << I2S_ERR_ICSS_INTC_SYS_EVT_BF_I2S_ERR_ICSS_INTC_SYS_EVT_SHIFT )
+
+/* FW_REG_I2S_PIN_NUM_ */
+#define BF_I2S_PIN_NUM_MASK ( 0xFF )
+#define I2S_PIN_NUM_BF_I2S_PIN_NUM_SHIFT ( 0 )
+#define I2S_PIN_NUM_BF_I2S_PIN_NUM_MASK ( BF_I2S_PIN_NUM_MASK << I2S_PIN_NUM_BF_I2S_PIN_NUM_SHIFT )
+
+/* FW_REG_TX_PING_PONG_SEL */
+#define BF_TX_PING_PONG_SEL_MASK ( 0x1 )
+#define TX_PING_PONG_SEL_BF_TX_PING_PONG_SEL_SHIFT ( 0 )
+#define TX_PING_PONG_SEL_BF_TX_PING_PONG_SEL_MASK ( BF_TX_PING_PONG_SEL_MASK << TX_PING_PONG_SEL_BF_TX_PING_PONG_SEL_SHIFT)
+
+/* FW_REG_RX_PING_PONG_SEL */
+#define BF_RX_PING_PONG_SEL_MASK ( 0x1 )
+#define RX_PING_PONG_SEL_BF_RX_PING_PONG_SEL_SHIFT ( 0 )
+#define RX_PING_PONG_SEL_BF_RX_PING_PONG_SEL_MASK ( BF_RX_PING_PONG_SEL_MASK << RX_PING_PONG_SEL_BF_RX_PING_PONG_SEL_SHIFT)
+
+/* FW_REG_TX_PING_PONG_STAT */
+#define BF_TX_PING_PONG_STAT_MASK ( 0x1 )
+#define TX_PING_PONG_STAT_BF_TX_PING_STAT_SHIFT ( 0 )
+#define TX_PING_PONG_STAT_BF_TX_PONG_STAT_SHIFT ( 1 )
+#define TX_PING_PONG_STAT_BF_TX_PING_STAT_MASK ( BF_TX_PING_PONG_STAT_MASK << TX_PING_PONG_STAT_BF_TX_PING_STAT_SHIFT )
+#define TX_PING_PONG_STAT_BF_TX_PONG_STAT_MASK ( BF_TX_PING_PONG_STAT_MASK << TX_PING_PONG_STAT_BF_TX_PONG_STAT_SHIFT )
+
+/* FW_REG_RX_PING_PONG_STAT */
+#define BF_RX_PING_PONG_STAT_MASK ( 0x1 )
+#define RX_PING_PONG_STAT_BF_RX_PING_STAT_SHIFT ( 0 )
+#define RX_PING_PONG_STAT_BF_RX_PONG_STAT_SHIFT ( 1 )
+#define RX_PING_PONG_STAT_BF_RX_PING_STAT_MASK ( BF_RX_PING_PONG_STAT_MASK << RX_PING_PONG_STAT_BF_RX_PING_STAT_SHIFT )
+#define RX_PING_PONG_STAT_BF_RX_PONG_STAT_MASK ( BF_RX_PING_PONG_STAT_MASK << RX_PING_PONG_STAT_BF_RX_PONG_STAT_SHIFT )
+
+/* FW_REG_ERR_STAT */
+#define BF_OVR_ERR_STAT_MASK ( 0x1 )
+#define BF_UND_ERR_STAT_MASK ( 0x1 )
+#define BF_FSYNC_ERR_STAT_MASK ( 0x1 )
+#define ERR_STAT_BF_OVR_ERR_STAT_SHIFT ( 0 )
+#define ERR_STAT_BF_UND_ERR_STAT_SHIFT ( 1 )
+#define ERR_STAT_BF_FSYNC_ERR_STAT_SHIFT ( 2 )
+#define ERR_STAT_BF_BF_OVR_ERR_STAT_MASK ( BF_OVR_ERR_STAT_MASK << ERR_STAT_BF_OVR_ERR_STAT_SHIFT )
+#define ERR_STAT_BF_BF_UND_ERR_STAT_MASK ( BF_UND_ERR_STAT_MASK << ERR_STAT_BF_UND_ERR_STAT_SHIFT )
+#define ERR_STAT_BF_BF_FSYNC_ERR_STAT_MASK ( BF_FSYNC_ERR_STAT_MASK << ERR_STAT_BF_FSYNC_ERR_STAT_SHIFT )
+
+#define PING_PONG_SEL_PING ( 0 )
+#define PING_PONG_SEL_PONG ( 1 )
+
+#endif /* _ICSS_PRUI2S_FW_H_ */
diff --git a/examples/pru_i2s/firmware/I2S/linker.cmd b/examples/pru_i2s/firmware/I2S/linker.cmd
new file mode 100644
index 000000000..b84523d29
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/linker.cmd
@@ -0,0 +1,88 @@
+/****************************************************************************/
+/* ICSSG_PRU.cmd */
+/* Copyright (c) 2025 Texas Instruments Incorporated */
+/* */
+/* Description: This file is a linker command file that can be used for */
+/* linking PRU programs built with the C compiler and */
+/* the resulting .out file on an pru device. */
+/****************************************************************************/
+
+/* -cr */ /* Link using C conventions */
+/* -stack 0x100 */
+
+/* Specify the System Memory Map */
+MEMORY
+{
+ PAGE 0:
+ PRU_IMEM : org = 0x00000000 len = 0x00004000 /* 16kB ICSSG_PRU Instruction RAM */
+
+ PAGE 1:
+
+ /* RAM */
+
+ PRU_DMEM_0_1_LOW : org = 0x00000000 len = 0x00001000 /* 4kB ICSSG Data RAM 0_1 for PRU*/
+ PRU_DMEM_0_1_HIGH : org = 0x00001000 len = 0x00001000 /* 4kB ICSSG Data RAM 0_1 for RTU*/
+ PRU_DMEM_1_0 : org = 0x00002000 len = 0x00002000 /* 8kB ICSSG Data RAM 1_0 */
+
+ PAGE 2:
+ PRU_SHAREDMEM : org = 0x00010000 len = 0x00010000 CREGISTER=28 /* 64kB Shared RAM */
+
+ /* Peripherals */
+
+ PRU_CFG : org = 0x00026000 len = 0x00000120 CREGISTER=4
+
+ RSVD0 : org = 0x00020000 len = 0x00001504 CREGISTER=0
+ RSVD1 : org = 0x48040000 len = 0x0000005C CREGISTER=1
+ RSVD2 : org = 0x4802A000 len = 0x000000D8 CREGISTER=2
+ RSVD3 : org = 0x00030000 len = 0x00000060 CREGISTER=3
+ RSVD5 : org = 0x48060000 len = 0x00000300 CREGISTER=5
+ RSVD6 : org = 0x48030000 len = 0x000001A4 CREGISTER=6
+ RSVD7 : org = 0x00028000 len = 0x00000038 CREGISTER=7
+ RSVD8 : org = 0x46000000 len = 0x00000100 CREGISTER=8
+ RSVD9 : org = 0x4A100000 len = 0x0000128C CREGISTER=9
+ RSVD10 : org = 0x48318000 len = 0x00000100 CREGISTER=10
+ RSVD11 : org = 0x48022000 len = 0x00000088 CREGISTER=11
+ RSVD12 : org = 0x48024000 len = 0x00000088 CREGISTER=12
+ RSVD13 : org = 0x48310000 len = 0x00000100 CREGISTER=13
+ RSVD14 : org = 0x481CC000 len = 0x000001E8 CREGISTER=14
+ RSVD15 : org = 0x481D0000 len = 0x000001E8 CREGISTER=15
+ RSVD16 : org = 0x481A0000 len = 0x000001A4 CREGISTER=16
+ RSVD17 : org = 0x4819C000 len = 0x000000D8 CREGISTER=17
+ RSVD18 : org = 0x48300000 len = 0x000002C4 CREGISTER=18
+ RSVD19 : org = 0x48302000 len = 0x000002C4 CREGISTER=19
+ RSVD20 : org = 0x48304000 len = 0x000002C4 CREGISTER=20
+ RSVD21 : org = 0x00032400 len = 0x00000100 CREGISTER=21
+ RSVD22 : org = 0x480C8000 len = 0x00000140 CREGISTER=22
+ RSVD23 : org = 0x480CA000 len = 0x00000880 CREGISTER=23
+ RSVD26 : org = 0x0002E000 len = 0x0000031C CREGISTER=26
+ RSVD27 : org = 0x00032000 len = 0x00000100 CREGISTER=27
+ RSVD29 : org = 0x49000000 len = 0x00001098 CREGISTER=29
+}
+
+/* Specify the sections allocation into memory */
+SECTIONS {
+ /* Forces _c_int00 to the start of PRU IRAM. Not necessary when loading
+ an ELF file, but useful when loading a binary */
+ /* .text:_c_int00* > 0x0, PAGE 0 */
+
+ /* .text > PRU_IMEM, PAGE 0 */
+ /* .stack > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .bss > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .cio > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .data > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .switch > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .sysmem > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .cinit > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .rodata > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .rofardata > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .farbss > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .fardata > PRU_DMEM_0_1_LOW, PAGE 1 */
+
+ .text > PRU_IMEM, PAGE 0
+ .data > PRU_DMEM_0_1_LOW, PAGE 1
+ .fwRegs > 0x0, PAGE 1
+
+ .outSamps > PRU_DMEM_0_1_LOW, PAGE 1
+
+ .dbgBuf > PRU_SHAREDMEM, PAGE 2
+}
diff --git a/examples/pru_i2s/firmware/I2S/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/example.projectspec b/examples/pru_i2s/firmware/I2S/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/example.projectspec
new file mode 100644
index 000000000..07a332784
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/example.projectspec
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/pru_i2s/firmware/I2S/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/makefile b/examples/pru_i2s/firmware/I2S/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/makefile
new file mode 100644
index 000000000..cd095de98
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/makefile
@@ -0,0 +1,91 @@
+################################################################################
+# PRU I2S - I2S Protocol - PRU0 TX - AM261x-LP
+################################################################################
+# Build firmware for PRU I2S transmit (TX) using I2S protocol
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+
+CG_TOOL_ROOT := $(CGT_TI_PRU_PATH)
+GEN_DIR := .
+
+# Add inputs and outputs from these tool invocations to the build variables
+CMD_SRCS += \
+ linker.cmd \
+
+ASM_SRCS += \
+ pru_i2s_main.asm \
+ fw_regs.asm \
+
+OBJS += \
+ pru_i2s_main.obj \
+ fw_regs.obj \
+
+ASM_DEPS += \
+ pru_i2s_main.d \
+ fw_regs.d \
+
+OBJDIR := .
+
+FILES_PATH_common = \
+ .. \
+ ../../.. \
+ ../../../.. \
+ ../../../../.. \
+
+FILES_PATH := $(FILES_PATH_common)
+
+vpath %.asm $(FILES_PATH)
+vpath %.obj $(OBJDIR)
+vpath %.cmd $(FILES_PATH)
+
+
+# Add inputs and outputs from these tool invocations to the build variables
+EXE_OUTPUTS += \
+pru_i2s_pru0_array_am261x-lp_icssm0-pru0_fw_ti-pru-cgt.out \
+
+EXE_OUTPUTS__QUOTED += \
+"pru_i2s_pru0_array_am261x-lp_icssm0-pru0_fw_ti-pru-cgt.out" \
+
+BIN_OUTPUTS += \
+pru_i2s_pru0_array_am261x-lp_icssm0-pru0_fw_ti-pru-cgt.hex \
+
+BIN_OUTPUTS__QUOTED += \
+"pru_i2s_pru0_array_am261x-lp_icssm0-pru0_fw_ti-pru-cgt.hex" \
+
+# All Target
+all: $(OBJS) $(CMD_SRCS)
+ @$(MAKE) --no-print-directory -Onone "pru_i2s_pru0_array_am261x-lp_icssm0-pru0_fw_ti-pru-cgt.out"
+
+# Each subdirectory must supply rules for building sources it contributes
+$(OBJDIR)/%.obj %.obj: %.asm
+ @echo 'Building file: "$^"'
+ @echo 'Invoking: PRU Compiler'
+ "$(CGT_TI_PRU_PATH)/bin/clpru" -DPRU0 -DSLICE0 -v4 --define=SOC_AM261X --define=PRU0 --define=I2S_TX --define=NUMBER_OF_TX_3 --define=I2S_TX_DETECT_UNDERFLOW --include_path="${CG_TOOL_ROOT}/include" --include_path="${MCU_PLUS_SDK_PATH}/source" --include_path="${OPEN_PRU_PATH}/source" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/include" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/I2S" --define=_DEBUG_=1 -g --diag_warning=225 --diag_wrap=off --display_error_number --endian=little --preproc_with_compile --preproc_dependency="$(basename $( ${OPEN_PRU_PATH}/examples/pru_i2s/firmware/I2S/pru_i2s_pru0_array.h
+ -$(RM) pru_i2s_pru0_array.h
+ -@echo ' '
+
+.PHONY: all clean
diff --git a/examples/pru_i2s/firmware/I2S/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/makefile_projectspec b/examples/pru_i2s/firmware/I2S/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/makefile_projectspec
new file mode 100644
index 000000000..b73b67b4e
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/makefile_projectspec
@@ -0,0 +1,20 @@
+#
+# Auto generated makefile
+#
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+
+PROFILE?=Release
+
+PROJECT_NAME=pru_i2s_pru0_array_am261x-lp_icssm0-pru0_fw_ti-pru-cgt
+
+all:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE)
+
+clean:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) -ccs.clean
+
+export:
+ $(MKDIR) $(OPEN_PRU_PATH)/ccs_projects
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectCreate -ccs.projectSpec example.projectspec -ccs.overwrite full
diff --git a/examples/pru_i2s/firmware/I2S/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/example.projectspec b/examples/pru_i2s/firmware/I2S/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/example.projectspec
new file mode 100644
index 000000000..f9e9e5031
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/example.projectspec
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/pru_i2s/firmware/I2S/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/makefile b/examples/pru_i2s/firmware/I2S/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/makefile
new file mode 100644
index 000000000..5b668523f
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/makefile
@@ -0,0 +1,90 @@
+################################################################################
+# PRU I2S Firmware Makefile
+################################################################################
+# Required input arguments :
+# Build firmware for PRU I2S Use this input argument to include files from external paths
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+CG_TOOL_ROOT := $(CGT_TI_PRU_PATH)
+
+# Add inputs and outputs from these tool invocations to the build variables
+CMD_SRCS += \
+ linker.cmd \
+
+ASM_SRCS += \
+ pru_i2s_main.asm \
+ fw_regs.asm \
+
+OBJS += \
+ pru_i2s_main.obj \
+ fw_regs.obj \
+
+ASM_DEPS += \
+ pru_i2s_main.d \
+ fw_regs.d \
+
+OBJDIR := .
+
+FILES_PATH_common = \
+ .. \
+ ../../.. \
+ ../../../.. \
+ ../../../../.. \
+
+FILES_PATH := $(FILES_PATH_common)
+
+vpath %.asm $(FILES_PATH)
+vpath %.obj $(OBJDIR)
+vpath %.cmd $(FILES_PATH)
+
+
+# Add inputs and outputs from these tool invocations to the build variables
+EXE_OUTPUTS += \
+pru_i2s_pru0_array_am263x-cc_icssm0-pru0_fw_ti-pru-cgt.out \
+
+EXE_OUTPUTS__QUOTED += \
+"pru_i2s_pru0_array_am263x-cc_icssm0-pru0_fw_ti-pru-cgt.out" \
+
+BIN_OUTPUTS += \
+pru_i2s_pru0_array_am263x-cc_icssm0-pru0_fw_ti-pru-cgt.hex \
+
+BIN_OUTPUTS__QUOTED += \
+"pru_i2s_pru0_array_am263x-cc_icssm0-pru0_fw_ti-pru-cgt.hex" \
+
+# All Target
+all: $(OBJS) $(CMD_SRCS)
+ @$(MAKE) --no-print-directory -Onone "pru_i2s_pru0_array_am263x-cc_icssm0-pru0_fw_ti-pru-cgt.out"
+
+# Each subdirectory must supply rules for building sources it contributes
+$(OBJDIR)/%.obj %.obj: %.asm
+ @echo 'Building file: "$^"'
+ @echo 'Invoking: PRU Compiler'
+ "$(CGT_TI_PRU_PATH)/bin/clpru" -DPRU0 -DSLICE0 -v4 --define=SOC_AM263X --define=PRU0 --define=I2S_TX --define=NUMBER_OF_TX_3 --define=I2S_TX_DETECT_UNDERFLOW --include_path="${CG_TOOL_ROOT}/include" --include_path="${MCU_PLUS_SDK_PATH}/source" --include_path="${OPEN_PRU_PATH}/source" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/include" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/I2S" --define=_DEBUG_=1 -g --diag_warning=225 --diag_wrap=off --display_error_number --endian=little --preproc_with_compile --preproc_dependency="$(basename $( ${OPEN_PRU_PATH}/examples/pru_i2s/firmware/I2S/pru_i2s_pru0_array.h
+ -$(RM) pru_i2s_pru0_array.h
+ -@echo ' '
+
+.PHONY: all clean
diff --git a/examples/pru_i2s/firmware/I2S/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/makefile_projectspec b/examples/pru_i2s/firmware/I2S/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/makefile_projectspec
new file mode 100644
index 000000000..00d5e107e
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/makefile_projectspec
@@ -0,0 +1,20 @@
+#
+# Auto generated makefile
+#
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+
+PROFILE?=Release
+
+PROJECT_NAME=pru_i2s_pru0_array_am263x-cc_icssm0-pru0_fw_ti-pru-cgt
+
+all:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE)
+
+clean:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) -ccs.clean
+
+export:
+ $(MKDIR) $(OPEN_PRU_PATH)/ccs_projects
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectCreate -ccs.projectSpec example.projectspec -ccs.overwrite full
diff --git a/examples/pru_i2s/firmware/I2S/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/example.projectspec b/examples/pru_i2s/firmware/I2S/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/example.projectspec
new file mode 100644
index 000000000..7551020a3
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/example.projectspec
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/pru_i2s/firmware/I2S/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/makefile b/examples/pru_i2s/firmware/I2S/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/makefile
new file mode 100644
index 000000000..a5a50b176
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/makefile
@@ -0,0 +1,90 @@
+################################################################################
+# PRU I2S Firmware Makefile
+################################################################################
+# Required input arguments :
+# Build firmware for PRU I2S Use this input argument to include files from external paths
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+CG_TOOL_ROOT := $(CGT_TI_PRU_PATH)
+
+# Add inputs and outputs from these tool invocations to the build variables
+CMD_SRCS += \
+ linker.cmd \
+
+ASM_SRCS += \
+ pru_i2s_main.asm \
+ fw_regs.asm \
+
+OBJS += \
+ pru_i2s_main.obj \
+ fw_regs.obj \
+
+ASM_DEPS += \
+ pru_i2s_main.d \
+ fw_regs.d \
+
+OBJDIR := .
+
+FILES_PATH_common = \
+ .. \
+ ../../.. \
+ ../../../.. \
+ ../../../../.. \
+
+FILES_PATH := $(FILES_PATH_common)
+
+vpath %.asm $(FILES_PATH)
+vpath %.obj $(OBJDIR)
+vpath %.cmd $(FILES_PATH)
+
+
+# Add inputs and outputs from these tool invocations to the build variables
+EXE_OUTPUTS += \
+pru_i2s_pru1_array_am261x-lp_icssm0-pru1_fw_ti-pru-cgt.out \
+
+EXE_OUTPUTS__QUOTED += \
+"pru_i2s_pru1_array_am261x-lp_icssm0-pru1_fw_ti-pru-cgt.out" \
+
+BIN_OUTPUTS += \
+pru_i2s_pru1_array_am261x-lp_icssm0-pru1_fw_ti-pru-cgt.hex \
+
+BIN_OUTPUTS__QUOTED += \
+"pru_i2s_pru1_array_am261x-lp_icssm0-pru1_fw_ti-pru-cgt.hex" \
+
+# All Target
+all: $(OBJS) $(CMD_SRCS)
+ @$(MAKE) --no-print-directory -Onone "pru_i2s_pru1_array_am261x-lp_icssm0-pru1_fw_ti-pru-cgt.out"
+
+# Each subdirectory must supply rules for building sources it contributes
+$(OBJDIR)/%.obj %.obj: %.asm
+ @echo 'Building file: "$^"'
+ @echo 'Invoking: PRU Compiler'
+ "$(CGT_TI_PRU_PATH)/bin/clpru" -DPRU1 -DSLICE1 -v4 --define=SOC_AM261X --define=PRU1 --define=I2S_RX --define=I2S_RX_DETECT_OVERFLOW --include_path="${CG_TOOL_ROOT}/include" --include_path="${MCU_PLUS_SDK_PATH}/source" --include_path="${OPEN_PRU_PATH}/source" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/include" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/I2S" --define=_DEBUG_=1 -g --diag_warning=225 --diag_wrap=off --display_error_number --endian=little --preproc_with_compile --preproc_dependency="$(basename $( ${OPEN_PRU_PATH}/examples/pru_i2s/firmware/I2S/pru_i2s_pru1_array.h
+ -$(RM) pru_i2s_pru1_array.h
+ -@echo ' '
+
+.PHONY: all clean
diff --git a/examples/pru_i2s/firmware/I2S/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/makefile_projectspec b/examples/pru_i2s/firmware/I2S/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/makefile_projectspec
new file mode 100644
index 000000000..a8d2863bd
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/makefile_projectspec
@@ -0,0 +1,20 @@
+#
+# Auto generated makefile
+#
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+
+PROFILE?=Release
+
+PROJECT_NAME=pru_i2s_pru1_array_am261x-lp_icssm0-pru1_fw_ti-pru-cgt
+
+all:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE)
+
+clean:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) -ccs.clean
+
+export:
+ $(MKDIR) $(OPEN_PRU_PATH)/ccs_projects
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectCreate -ccs.projectSpec example.projectspec -ccs.overwrite full
diff --git a/examples/pru_i2s/firmware/I2S/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/example.projectspec b/examples/pru_i2s/firmware/I2S/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/example.projectspec
new file mode 100644
index 000000000..19832aaf0
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/example.projectspec
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/pru_i2s/firmware/I2S/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/makefile b/examples/pru_i2s/firmware/I2S/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/makefile
new file mode 100644
index 000000000..428d1d57a
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/makefile
@@ -0,0 +1,90 @@
+################################################################################
+# PRU I2S Firmware Makefile
+################################################################################
+# Required input arguments :
+# Build firmware for PRU I2S Use this input argument to include files from external paths
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+CG_TOOL_ROOT := $(CGT_TI_PRU_PATH)
+
+# Add inputs and outputs from these tool invocations to the build variables
+CMD_SRCS += \
+ linker.cmd \
+
+ASM_SRCS += \
+ pru_i2s_main.asm \
+ fw_regs.asm \
+
+OBJS += \
+ pru_i2s_main.obj \
+ fw_regs.obj \
+
+ASM_DEPS += \
+ pru_i2s_main.d \
+ fw_regs.d \
+
+OBJDIR := .
+
+FILES_PATH_common = \
+ .. \
+ ../../.. \
+ ../../../.. \
+ ../../../../.. \
+
+FILES_PATH := $(FILES_PATH_common)
+
+vpath %.asm $(FILES_PATH)
+vpath %.obj $(OBJDIR)
+vpath %.cmd $(FILES_PATH)
+
+
+# Add inputs and outputs from these tool invocations to the build variables
+EXE_OUTPUTS += \
+pru_i2s_pru1_array_am263x-cc_icssm0-pru1_fw_ti-pru-cgt.out \
+
+EXE_OUTPUTS__QUOTED += \
+"pru_i2s_pru1_array_am263x-cc_icssm0-pru1_fw_ti-pru-cgt.out" \
+
+BIN_OUTPUTS += \
+pru_i2s_pru1_array_am263x-cc_icssm0-pru1_fw_ti-pru-cgt.hex \
+
+BIN_OUTPUTS__QUOTED += \
+"pru_i2s_pru1_array_am263x-cc_icssm0-pru1_fw_ti-pru-cgt.hex" \
+
+# All Target
+all: $(OBJS) $(CMD_SRCS)
+ @$(MAKE) --no-print-directory -Onone "pru_i2s_pru1_array_am263x-cc_icssm0-pru1_fw_ti-pru-cgt.out"
+
+# Each subdirectory must supply rules for building sources it contributes
+$(OBJDIR)/%.obj %.obj: %.asm
+ @echo 'Building file: "$^"'
+ @echo 'Invoking: PRU Compiler'
+ "$(CGT_TI_PRU_PATH)/bin/clpru" -DPRU1 -DSLICE1 -v4 --define=SOC_AM263X --define=PRU1 --define=I2S_RX --define=I2S_RX_DETECT_OVERFLOW --include_path="${CG_TOOL_ROOT}/include" --include_path="${MCU_PLUS_SDK_PATH}/source" --include_path="${OPEN_PRU_PATH}/source" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/include" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/I2S" --define=_DEBUG_=1 -g --diag_warning=225 --diag_wrap=off --display_error_number --endian=little --preproc_with_compile --preproc_dependency="$(basename $( ${OPEN_PRU_PATH}/examples/pru_i2s/firmware/I2S/pru_i2s_pru1_array.h
+ -$(RM) pru_i2s_pru1_array.h
+ -@echo ' '
+
+.PHONY: all clean
diff --git a/examples/pru_i2s/firmware/I2S/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/makefile_projectspec b/examples/pru_i2s/firmware/I2S/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/makefile_projectspec
new file mode 100644
index 000000000..f5fc5c064
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/makefile_projectspec
@@ -0,0 +1,20 @@
+#
+# Auto generated makefile
+#
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+
+PROFILE?=Release
+
+PROJECT_NAME=pru_i2s_pru1_array_am263x-cc_icssm0-pru1_fw_ti-pru-cgt
+
+all:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE)
+
+clean:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) -ccs.clean
+
+export:
+ $(MKDIR) $(OPEN_PRU_PATH)/ccs_projects
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectCreate -ccs.projectSpec example.projectspec -ccs.overwrite full
diff --git a/examples/pru_i2s/firmware/I2S/pru_i2s_interface.h b/examples/pru_i2s/firmware/I2S/pru_i2s_interface.h
new file mode 100644
index 000000000..bee866ad7
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru_i2s_interface.h
@@ -0,0 +1,213 @@
+ ;
+ ; Copyright (C) 2025 Texas Instruments Incorporated
+ ;
+ ; Redistribution and use in source and binary forms, with or without
+ ; modification, are permitted provided that the following conditions
+ ; are met:
+ ;
+ ; Redistributions of source code must retain the above copyright
+ ; notice, this list of conditions and the following disclaimer.
+ ;
+ ; Redistributions in binary form must reproduce the above copyright
+ ; notice, this list of conditions and the following disclaimer in the
+ ; documentation and/or other materials provided with the
+ ; distribution.
+ ;
+ ; Neither the name of Texas Instruments Incorporated nor the names of
+ ; its contributors may be used to endorse or promote products derived
+ ; from this software without specific prior written permission.
+ ;
+ ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ;
+
+ .if $isdefed("SOC_AM263X")
+ .if $isdefed("PRU0")
+I2S_INSTANCE_BCLK_PIN .set 6 ; PRG0_PRU0_GPOx
+I2S_INSTANCE_BCLK_PIN_POS .set 64 ; 2 << I2S_INSTANCE_BCLK_PIN
+
+I2S_INSTANCE_FS_PIN .set 1
+I2S_INSTANCE_FS_PIN_POS .set 2 ; 2 << I2S_INSTANCE_FS_PIN
+ .else
+I2S_INSTANCE_BCLK_PIN .set 0
+I2S_INSTANCE_BCLK_PIN_POS .set 1
+
+I2S_INSTANCE_FS_PIN .set 1
+I2S_INSTANCE_FS_PIN_POS .set 2
+ .endif
+
+ .if $isdefed("I2S_TX")
+ .if $isdefed("PRU0")
+I2S_INSTANCE1_SD_TX_PIN .set 2
+I2S_INSTANCE1_SD_TX_PIN_SHIFT .set I2S_INSTANCE1_SD_TX_PIN
+I2S_INSTANCE1_SD_TX_PIN_POS .set 4 ; 2 << I2S_INSTANCE1_SD_Tx_PIN
+
+I2S_INSTANCE2_SD_TX_PIN .set 3
+I2S_INSTANCE2_SD_TX_PIN_SHIFT .set I2S_INSTANCE2_SD_TX_PIN
+I2S_INSTANCE2_SD_TX_PIN_POS .set 8 ; 2 << I2S_INSTANCE2_SD_Tx_PIN
+
+I2S_INSTANCE3_SD_TX_PIN .set 5
+I2S_INSTANCE3_SD_TX_PIN_SHIFT .set I2S_INSTANCE3_SD_TX_PIN
+I2S_INSTANCE3_SD_TX_PIN_POS .set 32 ; 2 << I2S_INSTANCE3_SD_Tx_PIN
+ .else
+I2S_INSTANCE1_SD_TX_PIN .set 4
+I2S_INSTANCE1_SD_TX_PIN_SHIFT .set I2S_INSTANCE1_SD_TX_PIN
+I2S_INSTANCE1_SD_TX_PIN_POS .set 16 ; 2 << I2S_INSTANCE1_SD_Tx_PIN
+
+I2S_INSTANCE2_SD_TX_PIN .set 5
+I2S_INSTANCE2_SD_TX_PIN_SHIFT .set I2S_INSTANCE2_SD_TX_PIN
+I2S_INSTANCE2_SD_TX_PIN_POS .set 32 ; 2 << I2S_INSTANCE2_SD_Tx_PIN
+
+I2S_INSTANCE3_SD_TX_PIN .set 6
+I2S_INSTANCE3_SD_TX_PIN_SHIFT .set I2S_INSTANCE3_SD_TX_PIN
+I2S_INSTANCE3_SD_TX_PIN_POS .set 64 ; 2 << I2S_INSTANCE3_SD_Tx_PIN
+ .endif
+ .endif
+
+ .if $isdefed("I2S_RX")
+ .if $isdefed("PRU0")
+I2S_INSTANCE1_SD_RX_PIN .set 0
+I2S_INSTANCE1_SD_RX_PIN_SHIFT .set I2S_INSTANCE1_SD_RX_PIN
+I2S_INSTANCE1_SD_RX_PIN_POS .set 1 ; 2 << I2S_INSTANCE1_SD_Rx_PIN
+
+I2S_INSTANCE2_SD_RX_PIN .set 4
+I2S_INSTANCE2_SD_RX_PIN_SHIFT .set I2S_INSTANCE2_SD_RX_PIN
+I2S_INSTANCE2_SD_RX_PIN_POS .set 16 ; 2 << I2S_INSTANCE2_SD_Rx_PIN
+ .else
+I2S_INSTANCE1_SD_RX_PIN .set 2
+I2S_INSTANCE1_SD_RX_PIN_SHIFT .set I2S_INSTANCE1_SD_RX_PIN
+I2S_INSTANCE1_SD_RX_PIN_POS .set 4 ; 2 << I2S_INSTANCE1_SD_Rx_PIN
+
+I2S_INSTANCE2_SD_RX_PIN .set 3
+I2S_INSTANCE2_SD_RX_PIN_SHIFT .set I2S_INSTANCE2_SD_RX_PIN
+I2S_INSTANCE2_SD_RX_PIN_POS .set 8 ; 2 << I2S_INSTANCE2_SD_Rx_PIN
+ .endif
+ .endif
+ .endif ;SOC_AM263X
+ .if $isdefed("SOC_AM261X")
+ .if $isdefed("PRU0")
+; PRU0 Configuration
+I2S_INSTANCE_BCLK_PIN .set 5 ; PRU0 BCLK pin
+I2S_INSTANCE_BCLK_PIN_POS .set 32 ; 2 << 5
+
+I2S_INSTANCE_FS_PIN .set 6 ; PRU0 FSYNC pin
+I2S_INSTANCE_FS_PIN_POS .set 64 ; 2 << 6
+
+ .if $isdefed("I2S_TX")
+; PRU0 TX pins
+I2S_INSTANCE1_SD_TX_PIN .set 7 ; TX1
+I2S_INSTANCE1_SD_TX_PIN_SHIFT .set I2S_INSTANCE1_SD_TX_PIN
+I2S_INSTANCE1_SD_TX_PIN_POS .set 128 ; 2 << 7
+
+I2S_INSTANCE2_SD_TX_PIN .set 8 ; TX2
+I2S_INSTANCE2_SD_TX_PIN_SHIFT .set I2S_INSTANCE2_SD_TX_PIN
+I2S_INSTANCE2_SD_TX_PIN_POS .set 256 ; 2 << 8
+
+I2S_INSTANCE3_SD_TX_PIN .set 9 ; TX3
+I2S_INSTANCE3_SD_TX_PIN_SHIFT .set I2S_INSTANCE3_SD_TX_PIN
+I2S_INSTANCE3_SD_TX_PIN_POS .set 512 ; 2 << 9
+ .endif
+
+ .else
+; PRU1 Configuration
+I2S_INSTANCE_BCLK_PIN .set 5 ; PRU1 BCLK pin
+I2S_INSTANCE_BCLK_PIN_POS .set 32 ; 2 << 5
+
+I2S_INSTANCE_FS_PIN .set 9 ; PRU1 FSYNC pin
+I2S_INSTANCE_FS_PIN_POS .set 512 ; 2 << 9
+
+ .if $isdefed("I2S_RX")
+; PRU1 RX pins
+I2S_INSTANCE1_SD_RX_PIN .set 12 ; RX1
+I2S_INSTANCE1_SD_RX_PIN_SHIFT .set I2S_INSTANCE1_SD_RX_PIN
+I2S_INSTANCE1_SD_RX_PIN_POS .set 4096 ; 2 << 12
+
+I2S_INSTANCE2_SD_RX_PIN .set 13 ; RX2
+I2S_INSTANCE2_SD_RX_PIN_SHIFT .set I2S_INSTANCE2_SD_RX_PIN
+I2S_INSTANCE2_SD_RX_PIN_POS .set 8192 ; 2 << 13
+ .endif
+ .endif
+
+ .endif ;SOC_AM261X
+I2S_RXOVERFLOW_ERROR_POSITION .set 0
+I2S_TXUNDERFLOW_ERROR_POSITION .set 1
+I2S_FRAMESYNC_ERROR_POSITION .set 2
+
+;Address in FW Register space where TX PING address is stored
+I2S_TX_BUF_PING_ADD .set 4
+
+;Address in FW Register space where buffer size is stored. Buffer size is same for Tx and Rx. Buffer size is PING+PONG.
+I2S_PING_PONG_BUFSIZE_ADD .set 8
+
+;Address in FW Register space where RX PING address is stored
+I2S_RX_BUF_PING_ADD .set 0x14
+
+I2S_TX_BUF_PING_PONG_STAT_ADD .set 0x18
+
+I2S_RX_BUF_PING_PONG_STAT_ADD .set 0x19
+
+I2S_TX_INSTANCE_PING_PONG_STAT_ADD .set 0x1A
+
+I2S_RX_INSTANCE_PING_PONG_STAT_ADD .set 0x1B
+
+I2S_ERR_STAT_ADD .set 0x1C
+
+ .if $isdefed("NUMBER_OF_TX_2")
+;2 I2S instances of Tx only; Load 8 bytes from memory to register.
+BYTES_TO_LOAD .set 8
+ .endif
+ .if $isdefed("NUMBER_OF_TX_3")
+;3 I2S instances of Tx only. Load 12 bytes from memory to register.
+BYTES_TO_LOAD .set 12
+ .endif
+
+ .if $isdefed("PRU0")
+PRUx_CYCLE_CNT_REG_ADD .set 0x2200C; PRU0 cycle counter register address offset
+ .else
+PRUx_CYCLE_CNT_REG_ADD .set 0x2400C; PRU1 cycle counter register address offset
+ .endif
+;Number of samples per slot/channel
+I2S_SAMPLES_PER_CHANNEL .set 32
+I2S_SAMPLES_PER_CHANNEL_LESS_1 .set 31 ;I2S_SAMPLES_PER_CHANNEL-1
+ .if $isdefed("PRU0")
+; Compile-time Host event for I2S Tx, pr0_pru_mst_intr[2]_intr_req
+TRIGGER_HOST_I2S_TX_EVT .set 18 ; 2+16
+; R31 event interface mapping, add pru_r31_vec_valid to system event number
+TRIGGER_HOST_I2S_TX_IRQ .set TRIGGER_HOST_I2S_TX_EVT + 16 ; 2+16+16 = 2+32 = 2 + 1<<5
+
+; Compile-time Host event for I2S Rx, pr0_pru_mst_intr[3]_intr_req
+TRIGGER_HOST_I2S_RX_EVT .set 19 ; 3+16
+; R31 event interface mapping, add pru_r31_vec_valid to system event number
+TRIGGER_HOST_I2S_RX_IRQ .set TRIGGER_HOST_I2S_RX_EVT + 16 ; 3+16+16 = 3+32 = 3 + 1<<5
+
+; Compile-time Host event for I2S Error, pr0_pru_mst_intr[4]_intr_req
+TRIGGER_HOST_I2S_ERR_EVT .set 20 ; 4+16
+; R31 event interface mapping, add pru_r31_vec_valid to system event number
+TRIGGER_HOST_I2S_ERR_IRQ .set TRIGGER_HOST_I2S_ERR_EVT + 16 ; 4+16+16 = 4+32 = 4 + 1<<5
+
+ .else
+; Compile-time Host event for I2S Tx, pr0_pru_mst_intr[2]_intr_req
+TRIGGER_HOST_I2S_TX_EVT .set 21 ; 5+16
+; R31 event interface mapping, add pru_r31_vec_valid to system event number
+TRIGGER_HOST_I2S_TX_IRQ .set TRIGGER_HOST_I2S_TX_EVT + 16 ; 2+16+16 = 2+32 = 2 + 1<<5
+
+; Compile-time Host event for I2S Rx, pr0_pru_mst_intr[3]_intr_req
+TRIGGER_HOST_I2S_RX_EVT .set 22 ; 6+16
+; R31 event interface mapping, add pru_r31_vec_valid to system event number
+TRIGGER_HOST_I2S_RX_IRQ .set TRIGGER_HOST_I2S_RX_EVT + 16 ; 3+16+16 = 3+32 = 3 + 1<<5
+
+; Compile-time Host event for I2S Error, pr0_pru_mst_intr[4]_intr_req
+TRIGGER_HOST_I2S_ERR_EVT .set 23 ; 7+16
+; R31 event interface mapping, add pru_r31_vec_valid to system event number
+TRIGGER_HOST_I2S_ERR_IRQ .set TRIGGER_HOST_I2S_ERR_EVT + 16 ; 4+16+16 = 4+32 = 4 + 1<<5
+
+ .endif
diff --git a/examples/pru_i2s/firmware/I2S/pru_i2s_main.asm b/examples/pru_i2s/firmware/I2S/pru_i2s_main.asm
new file mode 100644
index 000000000..229b230c4
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru_i2s_main.asm
@@ -0,0 +1,502 @@
+ ;
+ ; Copyright (C) 2024-2025 Texas Instruments Incorporated
+ ;
+ ; Redistribution and use in source and binary forms, with or without
+ ; modification, are permitted provided that the following conditions
+ ; are met:
+ ;
+ ; Redistributions of source code must retain the above copyright
+ ; notice, this list of conditions and the following disclaimer.
+ ;
+ ; Redistributions in binary form must reproduce the above copyright
+ ; notice, this list of conditions and the following disclaimer in the
+ ; documentation and/or other materials provided with the
+ ; distribution.
+ ;
+ ; Neither the name of Texas Instruments Incorporated nor the names of
+ ; its contributors may be used to endorse or promote products derived
+ ; from this software without specific prior written permission.
+ ;
+ ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ;
+
+; this is intended to run on ICSSG0_PRU0/ICSSG0_PRU1
+
+ .sect ".text:main"
+ .clink
+ .global main
+
+ .include "pru_i2s_interface.h"
+ .include "pru_i2s_regs.h"
+
+main:
+ .if $isdefed("I2S_TX")
+ ;err_stat = err_stat >> 1. Remove the Rx Overflow error bit.
+ lsr err_stat, err_stat, 1
+ ;If there was an underflow/FrameSync Error, clearup thr Tx PingPong Buffer space
+ ;err_stat is already initialized during normal operation.
+ ; FS_ERROR UNDERFLOW_ERROR
+ ; 0 0 No Error
+ ; 0 1 Under Flow error
+ ; 1 0 FS Error
+ ; 1 1 Both errors
+ qbeq CONTIUNE_INIT, err_stat, 0
+ ;If set, this means underflow has happened.
+ ;Below Initializations can be avoided but after power on, registers
+ ;may contain random addresses and may result in accessing illegal addresses.
+ ldi ch0_data_tx, 0x0
+ ldi scratchreg0, 0x0
+ ldi tx_buf_size, 0x0
+ ldi scratchreg0, I2S_TX_BUF_PING_ADD
+ lbbo &tx_ping_buffer_address, scratchreg0, 0, 4
+ ldi scratchreg0, I2S_PING_PONG_BUFSIZE_ADD
+ lbbo &tx_buf_size, scratchreg0, 0, 2
+ add tx_buffer_address_end, tx_ping_buffer_address, tx_buf_size
+ZERO_TX_PING_PONG:
+ sbbo &ch0_data_tx, tx_ping_buffer_address, 0, 4
+ add tx_ping_buffer_address, tx_ping_buffer_address, 0x4
+ qbgt ZERO_TX_PING_PONG, tx_ping_buffer_address, tx_buffer_address_end
+ .endif
+
+CONTIUNE_INIT:
+ ;Clear registers R0-R29. 4*30=120 bytes
+ zero &r0, 128
+ ; Load pin mask registers
+ .if $isdefed("I2S_TX")
+ LDI i2s_instance_fs_pin_pos, I2S_INSTANCE_FS_PIN_POS
+ .endif
+ .if $isdefed("I2S_RX")
+ LDI i2s_instance_fs_pin_pos, I2S_INSTANCE_FS_PIN_POS
+ LDI i2s_instance1_sd_rx_pin_pos, I2S_INSTANCE1_SD_RX_PIN_POS
+ LDI i2s_instance2_sd_rx_pin_pos, I2S_INSTANCE2_SD_RX_PIN_POS
+ .endif
+
+ LDI scratchreg2, I2S_TX_INSTANCE_PING_PONG_STAT_ADD
+ LDI scratchreg0, 0x2
+ ;Store 0x2 into TX_PING_PONG_STAT
+ SBBO &scratchreg0, scratchreg2, 0, 1
+
+ ;I2S_RX_INSTANCE_PING_PONG_STAT_ADD = I2S_TX_INSTANCE_PING_PONG_STAT_ADD+1
+ LDI scratchreg0, 0x1
+ ;Store 0x1 into RX_PING_PONG_STAT
+ SBBO &scratchreg0, scratchreg2, 1, 1
+
+ ;Start with Ping Buffer
+ LDI tx_buffer_num, 0x1
+ ;Start with Ping Buffer
+ LDI rx_buffer_num, 0x1
+ LDI tx_sd_counter, I2S_SAMPLES_PER_CHANNEL_LESS_1
+
+ .if !$isdefed("I2S_TX")
+ .if $isdefed("I2S_RX")
+ ;Read the PING/PONG SEL address
+ LDI rx_ping_pong_sel_add, I2S_RX_BUF_PING_PONG_STAT_ADD
+ ;Read the PING/PONG STAT address
+ LDI rx_ping_pong_stat_add, I2S_RX_INSTANCE_PING_PONG_STAT_ADD
+ .endif
+ .endif
+
+ .if $isdefed("I2S_TX")
+ ;read the Tx buffer address provided by host. This should be in Shared memory
+ ; point to the PING audio buffer
+ LDI scratchreg0, I2S_TX_BUF_PING_ADD
+ LBBO &tx_buffer_address, scratchreg0, 0, 4
+ MOV tx_ping_buffer_address, tx_buffer_address
+ .endif
+
+ ;read the buffer size provided by host. buffer size is ping+pong
+ LDI scratchreg0, I2S_PING_PONG_BUFSIZE_ADD
+ LBBO &tx_buf_size, scratchreg0, 0, 2
+ ;Shift right by 1 to get PING/PONG size buffer size
+ LSR tx_buf_size, tx_buf_size, 1
+ .if $isdefed("I2S_RX")
+ MOV rx_buf_size, tx_buf_size
+ ;Rx buffer size is one less than PING/PONG buffer size
+ SUB rx_buf_size, rx_buf_size, 1
+
+ ;read the Rx buffer address provided by host
+ LDI scratchreg0, I2S_RX_BUF_PING_ADD
+ LBBO &rx_buffer_address, scratchreg0, 0, 4
+ MOV rx_ping_buffer_address, rx_buffer_address
+ LDI rx_sd_counter, I2S_SAMPLES_PER_CHANNEL
+ .endif
+
+ ;Initialize the end address of the Tx/Rx buffers
+ .if $isdefed("I2S_TX")
+ ADD tx_buffer_address_end, tx_buffer_address, tx_buf_size
+ .endif
+ .if $isdefed("I2S_RX")
+ ADD rx_buffer_address_end, rx_buffer_address, rx_buf_size
+ .endif
+
+ ;Initialize the PONG buffer addresses
+ .if $isdefed("I2S_TX")
+ MOV tx_pong_buffer_address, tx_buffer_address_end
+ .endif
+ .if $isdefed("I2S_RX")
+ MOV rx_pong_buffer_address, rx_buffer_address_end
+ ADD rx_pong_buffer_address, rx_pong_buffer_address, 1
+ .endif
+
+ .if $isdefed("I2S_TX")
+ ;Read the first 8/12 bytes from Ping buffer
+ LBBO &ch0_data_tx, tx_buffer_address, 0, BYTES_TO_LOAD
+ ADD tx_buffer_address, tx_buffer_address, BYTES_TO_LOAD
+ .endif
+
+INITIAL_STATE:
+ ; start iterating
+ ; wait until the input BCLK is low
+ ; then branch to wait for the rising edge
+ QBBS INITIAL_STATE, r31, I2S_INSTANCE_BCLK_PIN
+
+ ;Wait until there are 4 transitions of FS H-L-H-L-H
+INITIAL_STATE_FS:
+ ; start iterating
+ ; wait until the input FS is low
+ ; then branch to wait for the rising edge
+ QBBS INITIAL_STATE_FS, r31, I2S_INSTANCE_FS_PIN
+
+INITIAL_STATE_FS1:
+ ; wait until the input FS is high
+ QBBC INITIAL_STATE_FS1, r31, I2S_INSTANCE_FS_PIN
+
+INITIAL_STATE_FS2:
+ ; wait until the input FS is low
+ QBBS INITIAL_STATE_FS2, r31, I2S_INSTANCE_FS_PIN
+
+BCLK_RISING_EDGE_HIGH1:
+ QBBS BCLK_RISING_EDGE_HIGH1, r31, I2S_INSTANCE_BCLK_PIN
+
+BCLK_RISING_EDGE_LOW:
+ ; wait until we see a high value
+ QBBC BCLK_RISING_EDGE_LOW, r31, I2S_INSTANCE_BCLK_PIN
+ ; Read FS.
+ AND fs_level, r31, i2s_instance_fs_pin_pos
+ .if $isdefed("I2S_RX")
+ ;Read I2S1 Rx data
+ AND ch0_rx_val_reg, r31, i2s_instance1_sd_rx_pin_pos
+ ;Read I2S2 Rx data
+ AND ch1_rx_val_reg, r31, i2s_instance2_sd_rx_pin_pos
+
+ ;Once the buffer is full, switch to new buffer
+ QBGT MANAGE_RX_BUFFERS, rx_buffer_address_end, rx_buffer_address
+ .endif
+ .if $isdefed("I2S_TX")
+ .if !$isdefed("I2S_RX")
+CONTINUE_TX_PROCESSING:
+ .endif
+ .endif
+ ; if fs_counter = 0x0, then do tx buffer management
+ QBEQ MANAGE_TX_BUFFERS, fs_counter, 0x0
+ ;if fs_counter = max(fs_counter) -1, then check FS before expected FS transition
+ QBEQ CHECK_FS_1, fs_counter, I2S_SAMPLES_PER_CHANNEL-2
+ ;if fs_counter = max(fs_counter), then check FS after expected FS transition
+ QBEQ CHECK_FS_2, fs_counter, I2S_SAMPLES_PER_CHANNEL-1
+ ;if fs_counter = max(fs_counter) -2, then load audio data
+ QBEQ LOAD_AUDIO_DATA, fs_counter, I2S_SAMPLES_PER_CHANNEL-3
+ ;In case of Rx Only, Jump here after Sending Rx Notify to save PRU Cycles as we know fs_counter is 1.
+ .if !$isdefed("I2S_TX")
+ .if $isdefed("I2S_RX")
+CONTINUE_TX_PROCESSING:
+ .endif
+ .endif
+ ;else, increment fs_counter and wait for falling edge
+ ADD fs_counter, fs_counter, 0x1
+ .if $isdefed("I2S_TX_DETECT_UNDERFLOW")
+ ;Reset the variable here to save 1 cycle in BCLK LOW.
+ LDI do_tx_underflow_error_check, 0
+ .endif
+ ;if fs_counter = max(fs_counter)+1, then check FS after expected FS transition
+ QBGE CHECK_FS_3, fs_counter_1, 1
+ ;If not Jump
+ JMP BCLK_FALLING_EDGE_HIGH
+CHECK_FS_3:
+ LDI fs_counter_1, 0x0
+ LSR fs_level, fs_level, I2S_INSTANCE_FS_PIN
+ ; if fs_value != FS input we have an error
+ QBNE ERROR_HANDLING_FS, fs_level, fs_num
+ JMP BCLK_FALLING_EDGE_HIGH
+
+CHECK_FS_1:
+ ; if fs_counter = max(fs_counter) -1: Check for Early FS.
+ ; compare FS input to expected FS value
+ ; flip fs_value b/c we expect FS input to flip on the next cycle
+ ; put new audio sample in channel_data (loaded during a different BCLK high cycle)
+ ; if fs_value != FS input we have an error
+ ; Move the FS level to LSb position
+ LSR fs_level, fs_level, I2S_INSTANCE_FS_PIN
+ ; Compare FS levels
+ QBNE ERROR_HANDLING_FS, fs_level, fs_num
+
+ ; toggle fs_num bit between 0 (L channel) and 1 (R channel)
+ XOR fs_num, fs_num, 0x01
+
+ ; increment fs_counter and wait for falling edge
+ ADD fs_counter, fs_counter, 0x1
+ JMP BCLK_FALLING_EDGE_HIGH
+
+CHECK_FS_2:
+ ; if fs_counter = max(fs_counter):
+ ; Increment a second counter. Compare will be done after fs_counter = max(fs_counter)+1
+ ; reset fs_counter
+
+ ;Increment counter.
+ ADD fs_counter_1, fs_counter_1, 0x1
+
+ ; reset fs_counter and wait for falling edge
+ LDI fs_counter, 0x0
+ JMP BCLK_FALLING_EDGE_HIGH
+
+LOAD_AUDIO_DATA:
+ .if $isdefed("I2S_TX")
+ ; load audio data from ping-pong buffers
+ ; note that scratch registers must be sequential
+ LBBO &scratchreg0, tx_buffer_address, 0, BYTES_TO_LOAD
+ ADD tx_buffer_address, tx_buffer_address, BYTES_TO_LOAD
+ .endif
+ ; increment fs_counter and wait for falling edge
+ ADD fs_counter, fs_counter, 0x1
+ JMP BCLK_FALLING_EDGE_HIGH
+
+MANAGE_RX_BUFFERS:
+ .if $isdefed("I2S_RX")
+ ; if tx_buffer_address has reached the end of the buffer, point
+ ; to the beginning of the next buffer and notify the host core to
+ ; push fresh data to the buffer we just left.
+ ; if we are on buffer1, point to buffer2
+ QBEQ START_RX_BUFFER2, rx_buffer_num, 0x1
+
+ ; else, start buffer1
+ MOV rx_buffer_address, rx_ping_buffer_address
+ JMP RX_CONTINUE
+
+START_RX_BUFFER2:
+ MOV rx_buffer_address, rx_pong_buffer_address
+
+RX_CONTINUE:
+ ADD rx_buffer_address_end, rx_buffer_address, rx_buf_size
+ ; flip rx_buffer_num between 01_b and 01_b
+ XOR rx_buffer_num, rx_buffer_num, 0x1
+ SBBO &rx_buffer_num, rx_ping_pong_sel_add, 0, 1
+ ;set a condition to do Rx Overflow check
+ LDI do_rx_overflow_error_check, 1
+ ; notify the host
+ ;LDI R31.w0, TRIGGER_HOST_I2S_RX_IRQ
+ .endif ;I2S_RX
+ JMP CONTINUE_TX_PROCESSING
+
+MANAGE_TX_BUFFERS:
+ .if $isdefed("I2S_TX")
+ ; if tx_buffer_address has reached the end of the buffer, point
+ ; to the beginning of the next buffer and notify the host core to
+ ; push fresh data to the buffer we just left.
+ QBEQ START_NEW_BUFFER, tx_buffer_address, tx_buffer_address_end
+ .endif
+ ; increment fs_counter and wait for falling edge
+ ADD fs_counter, fs_counter, 0x1
+ JMP BCLK_FALLING_EDGE_HIGH
+
+START_NEW_BUFFER:
+ .if $isdefed("I2S_TX")
+ ; if we are on buffer1, point to buffer2
+ QBEQ START_BUFFER2, tx_buffer_num, 0x1
+
+ ; else, start buffer1
+ MOV tx_buffer_address, tx_ping_buffer_address
+ JMP CONTINUE
+
+START_BUFFER2:
+ MOV tx_buffer_address, tx_pong_buffer_address
+
+CONTINUE:
+ ADD tx_buffer_address_end, tx_buffer_address, tx_buf_size
+
+NOTIFY:
+ ; flip tx_buffer_num between 00_b and 01_b
+ XOR tx_buffer_num, tx_buffer_num, 0x1
+ LDI scratchreg2, I2S_TX_BUF_PING_PONG_STAT_ADD
+ SBBO &tx_buffer_num, scratchreg2, 0, 1
+ .if $isdefed("I2S_TX_DETECT_UNDERFLOW")
+ ;Read the Tx Ping Pong buffer stat from register address space
+ ;I2S_TX_INSTANCE_PING_PONG_STAT_ADD = I2S_TX_BUF_PING_PONG_STAT_ADD+2
+ LBBO &tx_ping_pong_stat, scratchreg2, 2, 1
+
+ ;If tx_buffer_num is 0, this means FW has already consumed PING buffer.
+ QBNE TX_PONG_BUF, tx_buffer_num, 0x0
+ ;Check if the PONG buffer has valid data
+ QBBC ERROR_HANDLING_UNDERFLOW, tx_ping_pong_stat, 1
+ ;If 1, this means PONG buffer has valid data. Clear the PING buffer status
+ CLR tx_ping_pong_stat, tx_ping_pong_stat, 0
+ JMP STORE_TX_PING_PONG_STAT
+
+TX_PONG_BUF:
+ ;Check if the PING buffer is full
+ QBBC ERROR_HANDLING_UNDERFLOW, tx_ping_pong_stat, 0
+ ;If 1, this means PING buffer has valid data. Clear the PONG buffer status
+ CLR tx_ping_pong_stat, tx_ping_pong_stat, 1
+
+STORE_TX_PING_PONG_STAT:
+ ;set a condition to perform some part of Tx Underflow in other half of BLCK
+ LDI do_tx_underflow_error_check, 1
+ ;SBBO &tx_ping_pong_stat, scratchreg2, 2, 1
+ .endif ;I2S_TX_DETECT_UNDERFLOW
+ ; notify the host
+ ;LDI R31.w0, TRIGGER_HOST_I2S_TX_IRQ
+ .endif ;I2S_TX
+ ; increment fs_counter and wait for falling edge
+ ADD fs_counter, fs_counter, 0x1
+BCLK_FALLING_EDGE_HIGH:
+ QBBS BCLK_FALLING_EDGE_HIGH, r31, I2S_INSTANCE_BCLK_PIN
+ .if $isdefed("I2S_TX")
+ .if $isdefed("I2S_TX_DETECT_UNDERFLOW")
+ QBNE CONTINUE_TX_PROCESS, do_tx_underflow_error_check, 0x1
+ ;Moved this to BCLK HIGH to save 1 cycle to meet I2S spec
+ ;LDI do_tx_underflow_error_check, 0
+ SBBO &tx_ping_pong_stat, scratchreg2, 2, 1
+ .endif ;I2S_TX_DETECT_UNDERFLOW
+ ; notify the host
+ LDI R31.w0, TRIGGER_HOST_I2S_TX_IRQ
+CONTINUE_TX_PROCESS:
+ .endif
+
+ .if $isdefed("I2S_RX")
+ .if $isdefed("I2S_RX_DETECT_OVERFLOW")
+ QBNE CONTINUE_RX_PROCESS, do_rx_overflow_error_check, 0x1
+ LDI do_rx_overflow_error_check, 0
+ ;Read the Rx Ping Pong buffer stat from register address space
+ LBBO &rx_ping_pong_stat, rx_ping_pong_stat_add, 0, 1
+
+ ;If rx_buffer_num is 0, this means FW has already filled PING buffer.
+ QBNE RX_PONG_BUF, rx_buffer_num, 0x0
+ ;Check if the PONG buffer is consumed by R5F. If consumed, bit 1 will be set to 0 by R5F, else it will be 1.
+ QBBS ERROR_HANDLING_OVERFLOW, rx_ping_pong_stat, 1
+ ;If 0, this means PONG buffer is consumed by R5F. SET the PING buffer status
+ SET rx_ping_pong_stat, rx_ping_pong_stat, 0
+ JMP STORE_RX_PING_PONG_STAT
+
+RX_PONG_BUF:
+ ;Check if the PING buffer is consumed by R5F. If consumed, bit 0 will be set to 0 by R5F, else it will be 1.
+ QBBS ERROR_HANDLING_OVERFLOW, rx_ping_pong_stat, 0
+ ;If 0, this means PING buffer is consumed by R5F. SET the PONG buffer status
+ ;OR rx_ping_pong_stat, rx_ping_pong_stat, 0x2
+ SET rx_ping_pong_stat, rx_ping_pong_stat, 1
+
+STORE_RX_PING_PONG_STAT:
+ SBBO &rx_ping_pong_stat, rx_ping_pong_stat_add, 0, 1
+ .endif ;I2S_RX_DETECT_OVERFLOW
+ ; notify the host
+ LDI R31.w0, TRIGGER_HOST_I2S_RX_IRQ
+ .endif
+CONTINUE_RX_PROCESS:
+ .if $isdefed("I2S_TX")
+ ; these 3 pseudoinstructions are used for each additional output bit
+ ; move the bit of audio data we are going to output next to the LSb of r30_value
+ LSR r30_value, ch0_data_tx, tx_sd_counter
+ LSR r30_value_1, ch1_data_tx, tx_sd_counter
+ .if $isdefed("NUMBER_OF_TX_3")
+ LSR r30_value_2, ch2_data_tx, tx_sd_counter
+ .endif
+ ;Remove other bits
+ AND r30_value, r30_value, 1
+ AND r30_value_1, r30_value_1, 1
+ .if $isdefed("NUMBER_OF_TX_3")
+ AND r30_value_2, r30_value_2, 1
+ .endif
+ ;Move the LSb to the required position
+ LSL r30_value, r30_value, I2S_INSTANCE1_SD_TX_PIN_SHIFT
+ LSL r30_value_1, r30_value_1, I2S_INSTANCE2_SD_TX_PIN_SHIFT
+ .if $isdefed("NUMBER_OF_TX_3")
+ LSL r30_value_2, r30_value_2, I2S_INSTANCE3_SD_TX_PIN_SHIFT
+ .endif
+
+ OR r30_value, r30_value, r30_value_1
+ .if $isdefed("NUMBER_OF_TX_3")
+ OR r30_value, r30_value, r30_value_2
+ .endif
+
+ ; write to R30 as soon as we see the falling clock edge
+ MOV r30, r30_value
+
+ ; if tx_sd_counter = 0, set to samples per channel 15/31
+ QBEQ RESET_SD_COUNTER, tx_sd_counter, 0
+
+ ; else, increment tx_sd_counter
+ SUB tx_sd_counter, tx_sd_counter, 0x1
+ .endif
+ JMP PREPARE_INPUT
+
+RESET_SD_COUNTER:
+ .if $isdefed("I2S_TX")
+ ; reset fs_counter and wait for falling edge
+ LDI tx_sd_counter, I2S_SAMPLES_PER_CHANNEL_LESS_1
+ MOV ch0_data_tx, scratchreg0
+ MOV ch1_data_tx, scratchreg1
+ .if $isdefed("NUMBER_OF_TX_3")
+ MOV ch2_data_tx, scratchreg2
+ .endif
+ .endif
+
+PREPARE_INPUT:
+ .if $isdefed("I2S_RX")
+ ; Receive Data
+ ; these 3 pseudoinstructions are used for each additional input bit
+ ; Skip for the first time since the first receive bit is valid after one bitclock after FS level change. See I2S spec.
+ QBEQ SKIP, rx_sd_counter, I2S_SAMPLES_PER_CHANNEL
+ ; Move the received bit to LSb position
+ LSR ch0_rx_val_reg, ch0_rx_val_reg, I2S_INSTANCE1_SD_RX_PIN_SHIFT
+ LSR ch1_rx_val_reg, ch1_rx_val_reg, I2S_INSTANCE2_SD_RX_PIN_SHIFT
+ ; Shift it to the required position
+ LSL ch0_rx_val_reg, ch0_rx_val_reg, rx_sd_counter
+ LSL ch1_rx_val_reg, ch1_rx_val_reg, rx_sd_counter
+ ; Append the bits of information to exisiting data
+ OR ch0_data_rx, ch0_data_rx, ch0_rx_val_reg
+ OR ch1_data_rx, ch1_data_rx, ch1_rx_val_reg
+ ; Once all the data is received, store the audio data.
+ QBEQ STORE_AUDIO_DATA, rx_sd_counter, 0
+
+SKIP:
+ SUB rx_sd_counter, rx_sd_counter, 1
+ .endif
+ JMP BCLK_RISING_EDGE_LOW
+
+STORE_AUDIO_DATA:
+ .if $isdefed("I2S_RX")
+ ; store 32 bits of audio data per channel.
+ SBBO &ch0_data_rx, rx_buffer_address, 0, 8
+ ADD rx_buffer_address, rx_buffer_address, 0x8
+ ; Reset ch0_rx_val_reg, ch1_rx_val_reg, ch0_data_rx, ch1_data_rx to 0. All these register must be continuous
+ ZERO &ch0_rx_val_reg, 16
+ LDI rx_sd_counter, I2S_SAMPLES_PER_CHANNEL_LESS_1
+ .endif
+ JMP BCLK_RISING_EDGE_LOW
+
+ERROR_HANDLING_OVERFLOW:
+ SET err_stat, err_stat, I2S_RXOVERFLOW_ERROR_POSITION
+ JMP ERROR_HANDLING_NOTIFY
+
+ERROR_HANDLING_UNDERFLOW:
+ SET err_stat, err_stat, I2S_TXUNDERFLOW_ERROR_POSITION
+ JMP ERROR_HANDLING_NOTIFY
+
+ERROR_HANDLING_FS:
+ SET err_stat, err_stat, I2S_FRAMESYNC_ERROR_POSITION
+
+ERROR_HANDLING_NOTIFY:
+ ;Load the ERR_STAT address into a scratch register
+ LDI scratchreg2, I2S_ERR_STAT_ADD
+ ;Store the error in to ERR_STAT
+ SBBO &err_stat, scratchreg2, 0, 1
+ ; notify the host
+ LDI R31.w0, TRIGGER_HOST_I2S_ERR_IRQ
+ JMP ||main||
diff --git a/examples/pru_i2s/firmware/I2S/pru_i2s_pru0_array.h b/examples/pru_i2s/firmware/I2S/pru_i2s_pru0_array.h
new file mode 100644
index 000000000..bf92fe82d
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru_i2s_pru0_array.h
@@ -0,0 +1,155 @@
+const uint32_t pru_prupru_i2s0_image_0_0[] = {
+0x0b015b5b,
+0x51005b0c,
+0x240000e4,
+0x240000f7,
+0x240000ea,
+0x240004f7,
+0xf1003782,
+0x240008f7,
+0xf100178a,
+0x00eae2e1,
+0xe1002284,
+0x0104e2e2,
+0x66e1e2fe,
+0x2effbf80,
+0x240002eb,
+0x24001af9,
+0x240002f7,
+0xe1001917,
+0x240001f7,
+0xe1011917,
+0x2400015a,
+0x2400017a,
+0x24001f1a,
+0x240004f7,
+0xf1003780,
+0x10e0e0e2,
+0x240008f7,
+0xf100178a,
+0x0b01eaea,
+0x00eae0e1,
+0x10e1e1e3,
+0xf100a084,
+0x010ce0e0,
+0xd106ff00,
+0xd101ff00,
+0xc901ff00,
+0xd101ff00,
+0xd106ff00,
+0xc906ff00,
+0x10ebfffc,
+0x51001619,
+0x511e160b,
+0x511f160f,
+0x511d1611,
+0x01011616,
+0x2400007b,
+0x71013602,
+0x21005500,
+0x24000036,
+0x0b01fcfc,
+0x6856fc40,
+0x21005500,
+0x0b01fcfc,
+0x6856fc3d,
+0x15015656,
+0x01011616,
+0x21005500,
+0x01013636,
+0x24000016,
+0x21005500,
+0xf100a097,
+0x010ce0e0,
+0x01011616,
+0x21005500,
+0x21002800,
+0x50e1e003,
+0x01011616,
+0x21005500,
+0x51015a03,
+0x10e2e2e0,
+0x21004800,
+0x10e3e3e0,
+0x00eae0e1,
+0x15015a5a,
+0x240018f9,
+0xe100195a,
+0xf102191b,
+0x69005a04,
+0xc9011b22,
+0x1d001b1b,
+0x21005300,
+0xc9001b1f,
+0x1d011b1b,
+0x2400017b,
+0x01011616,
+0xd106ff00,
+0x69017b03,
+0xe102191b,
+0x2400229f,
+0x0a1ae4e7,
+0x0a1ae5e8,
+0x0a1ae6e9,
+0x1101e7e7,
+0x1101e8e8,
+0x1101e9e9,
+0x0902e7e7,
+0x0903e8e8,
+0x0905e9e9,
+0x12e8e7e7,
+0x12e9e7e7,
+0x10e7e7fe,
+0x51001a03,
+0x05011a1a,
+0x21006c00,
+0x24001f1a,
+0x10f7f7e4,
+0x10f8f8e5,
+0x10f9f9e6,
+0x21002600,
+0x21002600,
+0x1f005b5b,
+0x21007300,
+0x1f015b5b,
+0x21007300,
+0x1f025b5b,
+0x24001cf9,
+0xe100195b,
+0x2400249f,
+0x21000000};
+
+const uint8_t pru_prupru_i2s0_image_0_1[] = {
+0x03,
+0x00,
+0x30,
+0x20,
+0x00,
+0x00,
+0x01,
+0x00,
+0x08,
+0x01,
+0x12,
+0x13,
+0x14,
+0x06,
+0x01,
+0x02,
+0x03,
+0x05,
+0x00,
+0x04,
+0x00,
+0x01,
+0x01,
+0x00,
+0x00,
+0x00,
+0x02,
+0x01,
+0x00,
+0x00,
+0x00,
+0x00};
+
diff --git a/examples/pru_i2s/firmware/I2S/pru_i2s_pru1_array.h b/examples/pru_i2s/firmware/I2S/pru_i2s_pru1_array.h
new file mode 100644
index 000000000..256234b95
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru_i2s_pru1_array.h
@@ -0,0 +1,142 @@
+const uint32_t pru_prupru_i2s1_image_0_0[] = {
+0x2effbf80,
+0x240002e7,
+0x240004e8,
+0x240008e9,
+0x24001af9,
+0x240002f7,
+0xe1001917,
+0x240001f7,
+0xe1011917,
+0x2400015a,
+0x2400017a,
+0x24001f1a,
+0x240019eb,
+0x24001bec,
+0x240008f7,
+0xf100178a,
+0x0b01eaea,
+0x10eaeaf1,
+0x0501f1f1,
+0x240014f7,
+0xf100378d,
+0x10ededef,
+0x2400203a,
+0x00f1edee,
+0x10eeeef0,
+0x0101f0f0,
+0xd100ff00,
+0xd101ff00,
+0xc901ff00,
+0xd101ff00,
+0xd100ff00,
+0xc900ff00,
+0x10e7fffc,
+0x10e8fff2,
+0x10e9fff3,
+0x60edee16,
+0x5100161e,
+0x511e160a,
+0x511f160e,
+0x511d1610,
+0x01011616,
+0x71013602,
+0x21004500,
+0x24000036,
+0x0b01fcfc,
+0x6856fc38,
+0x21004500,
+0x0b01fcfc,
+0x6856fc35,
+0x15015656,
+0x01011616,
+0x21004500,
+0x01013636,
+0x24000016,
+0x21004500,
+0x01011616,
+0x21004500,
+0x51017a03,
+0x10efefed,
+0x21003d00,
+0x10f0f0ed,
+0x00f1edee,
+0x15017a7a,
+0xe1000b7a,
+0x2400017b,
+0x21002800,
+0x01011616,
+0x21004500,
+0x01011616,
+0xd100ff00,
+0x69017b0b,
+0x2400007b,
+0xf1000c3b,
+0x69007a04,
+0xd1013b17,
+0x1f003b3b,
+0x21004f00,
+0xd1003b14,
+0x1f013b3b,
+0xe1000c3b,
+0x2400269f,
+0x21005200,
+0x51203a08,
+0x0b02f2f2,
+0x0b03f3f3,
+0x083af2f2,
+0x083af3f3,
+0x12f2f4f4,
+0x12f3f5f5,
+0x51003a03,
+0x05013a3a,
+0x21001f00,
+0xe1006d94,
+0x0108eded,
+0x2eff8792,
+0x24001f3a,
+0x21001f00,
+0x1f005b5b,
+0x21006600,
+0x1f015b5b,
+0x21006600,
+0x1f025b5b,
+0x24001cf9,
+0xe100195b,
+0x2400279f,
+0x21000000};
+
+const uint8_t pru_prupru_i2s1_image_0_1[] = {
+0x00,
+0x02,
+0x30,
+0x20,
+0x00,
+0x02,
+0x01,
+0x00,
+0x00,
+0x01,
+0x15,
+0x16,
+0x17,
+0x00,
+0x01,
+0x04,
+0x05,
+0x06,
+0x02,
+0x03,
+0x00,
+0x03,
+0x01,
+0x00,
+0x00,
+0x00,
+0x02,
+0x01,
+0x00,
+0x00,
+0x00,
+0x00};
+
diff --git a/examples/pru_i2s/firmware/I2S/pru_i2s_regs.h b/examples/pru_i2s/firmware/I2S/pru_i2s_regs.h
new file mode 100644
index 000000000..626ebccc1
--- /dev/null
+++ b/examples/pru_i2s/firmware/I2S/pru_i2s_regs.h
@@ -0,0 +1,113 @@
+ ;
+ ; Copyright (C) 2024-2025 Texas Instruments Incorporated
+ ;
+ ; Redistribution and use in source and binary forms, with or without
+ ; modification, are permitted provided that the following conditions
+ ; are met:
+ ;
+ ; Redistributions of source code must retain the above copyright
+ ; notice, this list of conditions and the following disclaimer.
+ ;
+ ; Redistributions in binary form must reproduce the above copyright
+ ; notice, this list of conditions and the following disclaimer in the
+ ; documentation and/or other materials provided with the
+ ; distribution.
+ ;
+ ; Neither the name of Texas Instruments Incorporated nor the names of
+ ; its contributors may be used to endorse or promote products derived
+ ; from this software without specific prior written permission.
+ ;
+ ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ;
+
+; define registers
+ .if $isdefed("I2S_PROFILE_FW")
+prux_cycle_cnt_0 .set r0
+prux_cycle_cnt_1 .set r1
+scratchreg_cycle_cnt .set r2
+prux_cycle_cnt .set r3
+cnt_buffer_address .set r4
+cnt_buffer_address_1 .set r5
+ .endif
+
+; Pin mask registers
+ .if !$isdefed("I2S_RX")
+i2s_instance_fs_pin_pos .set r11
+ .else
+i2s_instance_fs_pin_pos .set r7
+i2s_instance1_sd_rx_pin_pos .set r8
+i2s_instance2_sd_rx_pin_pos .set r9
+ .endif
+
+ .if !$isdefed("I2S_RX")
+;In case of Tx only, use some of the Rx registers.
+; tx_buffer_address keeps track of where we are in the audio buffer
+tx_buffer_address .set r0
+tx_buffer_address_end .set r1
+tx_ping_buffer_address .set r2
+tx_pong_buffer_address .set r3
+; ch0_data_tx is 16/32 bit audio sample
+ch0_data_tx .set r4
+ch1_data_tx .set r5
+ch2_data_tx .set r6
+r30_value .set r7
+r30_value_1 .set r8
+r30_value_2 .set r9
+ .endif
+
+tx_buf_size .set r10
+
+ .if $isdefed("I2S_RX")
+rx_ping_pong_sel_add .set r11
+rx_ping_pong_stat_add .set r12
+rx_buffer_address .set r13
+rx_buffer_address_end .set r14
+rx_ping_buffer_address .set r15
+rx_pong_buffer_address .set r16
+rx_buf_size .set r17
+;Read receive data
+ch0_rx_val_reg .set r18
+ch1_rx_val_reg .set r19
+;Accumulate receive data
+ch0_data_rx .set r20
+ch1_data_rx .set r21
+ .endif
+
+ ; fs_counter counts 16/32 clocks per frame sync
+ .asg r22.b0, fs_counter
+ ; fs_counter_1 used to compare FS after transition
+ .asg r22.b1, fs_counter_1
+ ; fs_num is frame sync number
+ ; 00_b (0) is L channel, 10_b (2) is R channel
+ .asg r22.b2, fs_num
+ .asg r28, fs_level
+
+scratchreg0 .set r23
+scratchreg1 .set r24
+scratchreg2 .set r25
+
+ .asg r26.b0, tx_sd_counter
+ .asg r26.b1, rx_sd_counter
+ ; this FW uses 2 buffers, tx_buffer_num says which buffer is current
+ .asg r26.b2, tx_buffer_num
+ .asg r26.b3, rx_buffer_num
+
+ .asg r27.b0, tx_ping_pong_stat
+ .asg r27.b1, rx_ping_pong_stat
+ .asg r27.b2, err_stat
+ .if $isdefed("I2S_RX")
+ .asg r27.b3, do_rx_overflow_error_check
+ .endif
+ .if $isdefed("I2S_TX")
+ .asg r27.b3, do_tx_underflow_error_check
+ .endif
diff --git a/examples/pru_i2s/firmware/TDM4/fw_regs.asm b/examples/pru_i2s/firmware/TDM4/fw_regs.asm
new file mode 100644
index 000000000..fd854da92
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/fw_regs.asm
@@ -0,0 +1,113 @@
+ ;
+ ; Copyright (C) 2024-2025 Texas Instruments Incorporated
+ ;
+ ; Redistribution and use in source and binary forms, with or without
+ ; modification, are permitted provided that the following conditions
+ ; are met:
+ ;
+ ; Redistributions of source code must retain the above copyright
+ ; notice, this list of conditions and the following disclaimer.
+ ;
+ ; Redistributions in binary form must reproduce the above copyright
+ ; notice, this list of conditions and the following disclaimer in the
+ ; documentation and/or other materials provided with the
+ ; distribution.
+ ;
+ ; Neither the name of Texas Instruments Incorporated nor the names of
+ ; its contributors may be used to endorse or promote products derived
+ ; from this software without specific prior written permission.
+ ;
+ ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ;
+
+ .cdecls C,NOLIST
+%{
+ #include "icss_pru_i2s_fw.h"
+%}
+
+ ; PRU I2S Firmware Registers
+ .sect ".fwRegs"
+ .retain ".fwRegs"
+ .retainrefs ".fwRegs"
+ .space ICSS_PRUI2S_FW_REG_BASE
+ .if $isdefed("NUMBER_OF_TX_2")
+ .byte 2 ; NUM_TX_I2S
+ .endif
+ .if $isdefed("NUMBER_OF_TX_3")
+ .byte 3 ; NUM_TX_I2S
+ .endif
+ .if !$isdefed("NUMBER_OF_TX_2")
+ .if !$isdefed("NUMBER_OF_TX_3")
+ .byte 0 ; NUM_TX_I2S
+ .endif
+ .endif
+ .if $isdefed("I2S_RX")
+ .byte 2 ; NUM_RX_I2S
+ .else
+ .byte 0 ; NUM_RX_I2S
+ .endif
+ .byte 48 ; SAMP_FREQ
+ .if $isdefed("SOC_AM64X")
+ .byte 16 ; BITS_PER_SLOT
+ .else
+ .byte 32 ; BITS_PER_SLOT
+ .endif
+ .if $isdefed("PRU0")
+ .word 0x10000 ; TX_PING_PONG_BUF_ADDR
+ .else
+ .word 0x10200 ; TX_PING_PONG_BUF_ADDR
+ .endif
+ .if $isdefed("NUMBER_OF_TX_3")
+ .short 264 ; PING_PONG_BUF_SZ
+ .else
+ .short 256 ; PING_PONG_BUF_SZ
+ .endif
+ .if $isdefed("PRU0")
+ .byte 18 ; I2S_TX_ICSS_INTC_SYS_EVT (Event 18=16+2)
+ .byte 19 ; I2S_RX_ICSS_INTC_SYS_EVT (Event 19=16+3)
+ .byte 20 ; I2S_ERR_ICSS_INTC_SYS_EVT (Event 20=16+4)
+ .else
+ .byte 21 ; I2S_TX_ICSS_INTC_SYS_EVT (Event 21=16+5)
+ .byte 22 ; I2S_RX_ICSS_INTC_SYS_EVT (Event 22=16+6)
+ .byte 23 ; I2S_ERR_ICSS_INTC_SYS_EVT (Event 23=16+7)
+ .endif
+
+ .if $isdefed("PRU0")
+ .byte 6 ; PIN_NUM_BCLK
+ .byte 1 ; PIN_NUM_FSYNC
+ .byte 2 ; PIN_NUM_TX0/RESERVED in case of RX Only
+ .byte 3 ; PIN_NUM_TX1/RESERVED in case of RX Only
+ .byte 5 ; PIN_NUM_TX2/RESERVED in case of RX Only/2Tx Only
+ .byte 0 ; PIN_NUM_RX0
+ .byte 4 ; PIN_NUM_RX1
+ .else
+ .byte 0 ; PIN_NUM_BCLK
+ .byte 1 ; PIN_NUM_FSYNC
+ .byte 4 ; PIN_NUM_TX0/RESERVED in case of RX Only
+ .byte 5 ; PIN_NUM_TX1/RESERVED in case of RX Only
+ .byte 6 ; PIN_NUM_TX2/RESERVED in case of RX Only/2Tx Only
+ .byte 2 ; PIN_NUM_RX0
+ .byte 3 ; PIN_NUM_RX1
+ .endif
+
+ .if $isdefed("PRU0")
+ .word 0x10100 ; RX_PING_PONG_BUF_ADDR
+ .else
+ .word 0x10300 ; RX_PING_PONG_BUF_ADDR
+ .endif
+ .byte 0 ; TX_PING_PONG_SEL
+ .byte 0 ; RX_PING_PONG_SEL
+ .byte 2 ; TX_PING_PONG_STAT
+ .byte 1 ; RX_PING_PONG_STAT
+ .byte 0 ; ERR_STAT
+
diff --git a/examples/pru_i2s/firmware/TDM4/icss_pru_i2s_fw.h b/examples/pru_i2s/firmware/TDM4/icss_pru_i2s_fw.h
new file mode 100644
index 000000000..741a0b9ad
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/icss_pru_i2s_fw.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ICSS_pru_i2s_FW_H_
+#define _ICSS_pru_i2s_FW_H_
+
+/*
+ Firmware registers
+*/
+
+/* FW register base address */
+#define ICSS_PRUI2S_FW_REG_BASE ( 0x0000 )
+
+/* FW register sizes (in bytes) */
+#define FW_REG_NUM_TX_I2S_SZ ( 1 )
+#define FW_REG_NUM_RX_I2S_SZ ( 1 )
+#define FW_REG_SAMP_FREQ_SZ ( 1 )
+#define FW_REG_BITS_PER_SLOT_SZ ( 1 )
+#define FW_REG_TX_PING_PONG_BUF_ADDR_SZ ( 4 )
+#define FW_REG_PING_PONG_BUF_SZ_SZ ( 2 )
+#define FW_REG_I2S_ICSS_INTC_SYS_EVT_SZ ( 1 )
+#define FW_REG_I2S_ERR_ICSS_INTC_SYS_EVT_SZ ( 1 )
+#define FW_REG_I2S_PIN_NUM_SZ ( 1 )
+
+/* FW register offsets from base (in bytes) */
+#define FW_REG_NUM_TX_I2S_OFFSET ( 0x00 )
+#define FW_REG_NUM_RX_I2S_OFFSET ( 0x01 )
+#define FW_REG_SAMP_FREQ_OFFSET ( 0x02 )
+#define FW_REG_BITS_PER_SLOT_OFFSET ( 0x03 )
+#define FW_REG_TX_PING_PONG_BUF_ADDR_OFFSET ( 0x04 )
+#define FW_REG_PING_PONG_BUF_SZ_OFFSET ( 0x08 )
+#define FW_REG_I2S_TX_ICSS_INTC_SYS_EVT_OFFSET ( 0x0A )
+#define FW_REG_I2S_RX_ICSS_INTC_SYS_EVT_OFFSET ( 0x0B )
+#define FW_REG_I2S_ERR_ICSS_INTC_SYS_EVT_OFFSET ( 0x0C )
+#define FW_REG_I2S_PIN_NUM_BCLK_OFFSET ( 0x0D )
+#define FW_REG_I2S_PIN_NUM_FSYNC_OFFSET ( 0x0E )
+#define FW_REG_I2S_PIN_NUM_TX0_OFFSET ( 0x0F )
+#define FW_REG_I2S_PIN_NUM_TX1_OFFSET ( 0x10 )
+#define FW_REG_I2S_PIN_NUM_TX2_OFFSET ( 0x11 )
+#define FW_REG_I2S_PIN_NUM_RX0_OFFSET ( 0x12 )
+#define FW_REG_I2S_PIN_NUM_RX1_OFFSET ( 0x13 )
+#define FW_REG_RX_PING_PONG_BUF_ADDR_OFFSET ( 0x14 )
+#define FW_REG_TX_PING_PONG_SEL_OFFSET ( 0x18 )
+#define FW_REG_RX_PING_PONG_SEL_OFFSET ( 0x19 )
+#define FW_REG_TX_PING_PONG_STAT_OFFSET ( 0x1A )
+#define FW_REG_RX_PING_PONG_STAT_OFFSET ( 0x1B )
+#define FW_REG_ERR_STAT_OFFSET ( 0x1C )
+
+/* FW register addresses */
+#define FW_REG_NUM_TX_I2S ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_NUM_TX_I2S_OFFSET )
+#define FW_REG_NUM_RX_I2S ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_NUM_RX_I2S_OFFSET )
+#define FW_REG_SAMP_FREQ ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_SAMP_FREQ_OFFSET )
+#define FW_REG_BITS_PER_SLOT ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_BITS_PER_SLOT_OFFSET )
+#define FW_REG_TX_PING_PONG_BUF_ADDR ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_TX_PING_PONG_BUF_ADDR_OFFSET )
+#define FW_REG_PING_PONG_BUF_SZ ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_PING_PONG_BUF_SZ_OFFSET )
+#define FW_REG_I2S_TX_ICSS_INTC_SYS_EVT ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_TX_ICSS_INTC_SYS_EVT_OFFSET )
+#define FW_REG_I2S_RX_ICSS_INTC_SYS_EVT ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_RX_ICSS_INTC_SYS_EVT_OFFSET )
+#define FW_REG_I2S_ERR_ICSS_INTC_SYS_EVT ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_ERR_ICSS_INTC_SYS_EVT_OFFSET )
+#define FW_REG_I2S_PIN_NUM_BCLK ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_PIN_NUM_BCLK_OFFSET )
+#define FW_REG_I2S_PIN_NUM_FSYNC ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_PIN_NUM_FSYNC_OFFSET )
+#define FW_REG_I2S_PIN_NUM_TX0 ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_PIN_NUM_TX0_OFFSET )
+#define FW_REG_I2S_PIN_NUM_TX1 ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_PIN_NUM_TX1_OFFSET )
+#define FW_REG_I2S_PIN_NUM_TX2 ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_PIN_NUM_TX2_OFFSET )
+#define FW_REG_I2S_PIN_NUM_RX0 ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_PIN_NUM_RX0_OFFSET )
+#define FW_REG_I2S_PIN_NUM_RX1 ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_I2S_PIN_NUM_RX1_OFFSET )
+#define FW_REG_RX_PING_PONG_BUF_ADDR ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_RX_PING_PONG_BUF_ADDR_OFFSET )
+#define FW_REG_TX_PING_PONG_SEL ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_TX_PING_PONG_SEL_OFFSET )
+#define FW_REG_RX_PING_PONG_SEL ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_RX_PING_PONG_SEL_OFFSET )
+#define FW_REG_TX_PING_PONG_STAT ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_TX_PING_PONG_STAT_OFFSET )
+#define FW_REG_RX_PING_PONG_STAT ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_RX_PING_PONG_STAT_OFFSET )
+#define FW_REG_ERR_STAT ( ICSS_PRUI2S_FW_REG_BASE + FW_REG_ERR_STAT_OFFSET )
+
+/*
+ Firmware register bit fields
+*/
+
+/* NUM_TX_I2S */
+#define BF_NUM_TX_I2S_MASK ( 0x3 )
+#define NUM_TX_I2S_BF_NUM_TX_I2S_SHIFT ( 0 )
+#define NUM_TX_I2S_BF_NUM_TX_I2S_MASK ( BF_NUM_TX_I2S_MASK << NUM_TX_I2S_BF_NUM_TX_I2S_SHIFT )
+
+/* NUM_RX_I2S */
+#define BF_NUM_RX_I2S_MASK ( 0x3 )
+#define NUM_TX_I2S_BF_NUM_RX_I2S_SHIFT ( 0 )
+#define NUM_TX_I2S_BF_NUM_RX_I2S_MASK ( BF_NUM_RX_I2S_MASK << NUM_TX_I2S_BF_NUM_RX_I2S_SHIFT )
+
+/* FW_REG_SAMP_FREQ */
+#define BF_SAMP_FREQ_MASK ( 0xFF )
+#define SAMP_FREQ_BF_SAMP_FREQ_SHIFT ( 0 )
+#define SAMP_FREQ_BF_SAMP_FREQ_MASK ( BF_SAMP_FREQ_MASK << SAMP_FREQ_BF_SAMP_FREQ_SHIFT )
+
+/* FW_REG_BITS_PER_SLOT */
+#define BF_BITS_PER_SLOT_MASK ( 0x1F )
+#define BITS_PER_SLOT_BF_BITS_PER_SLOT_SHIFT ( 0 )
+#define BITS_PER_SLOT_BF_BITS_PER_SLOT_MASK ( BF_BITS_PER_SLOT_MASK << BITS_PER_SLOT_BF_BITS_PER_SLOT_SHIFT )
+
+/* FW_REG_TX_PING_PONG_BUF_ADDR */
+#define BF_TX_BUF_PING_PONG_BUF_ADDR_MASK ( 0xFFFFFFFF )
+#define TX_BUF_PING_PONG_BUF_ADDR_BF_TX_BUF_PING_PONG_BUF_ADDR_SHIFT \
+ ( 0 )
+#define TX_BUF_PING_PONG_BUF_ADDR_BF_TX_BUF_PING_PONG_BUF_ADDR_MASK \
+ ( BF_TX_BUF_PING_PONG_BUF_ADDR_MASK << TX_BUF_PING_PONG_BUF_ADDR_BF_TX_BUF_PING_PONG_BUF_ADDR_SHIFT )
+
+/* FW_REG_PING_PONG_BUF_SZ */
+#define BF_PING_PONG_BUF_SZ_MASK ( 0xFFFF )
+#define TX_PING_PONG_BUF_SZ_BF_PING_PONG_BUF_SZ_SHIFT \
+ ( 0 )
+#define TX_PING_PONG_BUF_SZ_BF_PING_PONG_BUF_SZ_MASK \
+ ( BF_PING_PONG_BUF_SZ_MASK << TX_PING_PONG_BUF_SZ_BF_PING_PONG_BUF_SZ_SHIFT )
+
+/* FW_REG_I2S_ICSS_INTC_SYS_EVT */
+#define BF_I2S_ICSS_INTC_SYS_EVT_MASK ( 0xFF )
+#define I2S_ICSS_INTC_SYS_EVT_BF_I2S_ICSS_INTC_SYS_EVT_SHIFT \
+ ( 0 )
+#define I2S_ICSS_INTC_SYS_EVT_BF_I2S_ICSS_INTC_SYS_EVT_MASK \
+ ( BF_I2S_ICSS_INTC_SYS_EVT_MASK << I2S_ICSS_INTC_SYS_EVT_BF_I2S_ICSS_INTC_SYS_EVT_SHIFT )
+
+/* FW_REG_I2S_ERR_ICSS_INTC_SYS_EVT */
+#define BF_I2S_ERR_ICSS_INTC_SYS_EVT_MASK ( 0xFF )
+#define I2S_ERR_ICSS_INTC_SYS_EVT_BF_I2S_ERR_ICSS_INTC_SYS_EVT_SHIFT \
+ ( 0 )
+#define I2S_ERR_ICSS_INTC_SYS_EVT_BF_I2S_ERR_ICSS_INTC_SYS_EVT_MASK \
+ ( BF_I2S_ERR_ICSS_INTC_SYS_EVT_MASK << I2S_ERR_ICSS_INTC_SYS_EVT_BF_I2S_ERR_ICSS_INTC_SYS_EVT_SHIFT )
+
+/* FW_REG_I2S_PIN_NUM_ */
+#define BF_I2S_PIN_NUM_MASK ( 0xFF )
+#define I2S_PIN_NUM_BF_I2S_PIN_NUM_SHIFT ( 0 )
+#define I2S_PIN_NUM_BF_I2S_PIN_NUM_MASK ( BF_I2S_PIN_NUM_MASK << I2S_PIN_NUM_BF_I2S_PIN_NUM_SHIFT )
+
+/* FW_REG_TX_PING_PONG_SEL */
+#define BF_TX_PING_PONG_SEL_MASK ( 0x1 )
+#define TX_PING_PONG_SEL_BF_TX_PING_PONG_SEL_SHIFT ( 0 )
+#define TX_PING_PONG_SEL_BF_TX_PING_PONG_SEL_MASK ( BF_TX_PING_PONG_SEL_MASK << TX_PING_PONG_SEL_BF_TX_PING_PONG_SEL_SHIFT)
+
+/* FW_REG_RX_PING_PONG_SEL */
+#define BF_RX_PING_PONG_SEL_MASK ( 0x1 )
+#define RX_PING_PONG_SEL_BF_RX_PING_PONG_SEL_SHIFT ( 0 )
+#define RX_PING_PONG_SEL_BF_RX_PING_PONG_SEL_MASK ( BF_RX_PING_PONG_SEL_MASK << RX_PING_PONG_SEL_BF_RX_PING_PONG_SEL_SHIFT)
+
+/* FW_REG_TX_PING_PONG_STAT */
+#define BF_TX_PING_PONG_STAT_MASK ( 0x1 )
+#define TX_PING_PONG_STAT_BF_TX_PING_STAT_SHIFT ( 0 )
+#define TX_PING_PONG_STAT_BF_TX_PONG_STAT_SHIFT ( 1 )
+#define TX_PING_PONG_STAT_BF_TX_PING_STAT_MASK ( BF_TX_PING_PONG_STAT_MASK << TX_PING_PONG_STAT_BF_TX_PING_STAT_SHIFT )
+#define TX_PING_PONG_STAT_BF_TX_PONG_STAT_MASK ( BF_TX_PING_PONG_STAT_MASK << TX_PING_PONG_STAT_BF_TX_PONG_STAT_SHIFT )
+
+/* FW_REG_RX_PING_PONG_STAT */
+#define BF_RX_PING_PONG_STAT_MASK ( 0x1 )
+#define RX_PING_PONG_STAT_BF_RX_PING_STAT_SHIFT ( 0 )
+#define RX_PING_PONG_STAT_BF_RX_PONG_STAT_SHIFT ( 1 )
+#define RX_PING_PONG_STAT_BF_RX_PING_STAT_MASK ( BF_RX_PING_PONG_STAT_MASK << RX_PING_PONG_STAT_BF_RX_PING_STAT_SHIFT )
+#define RX_PING_PONG_STAT_BF_RX_PONG_STAT_MASK ( BF_RX_PING_PONG_STAT_MASK << RX_PING_PONG_STAT_BF_RX_PONG_STAT_SHIFT )
+
+/* FW_REG_ERR_STAT */
+#define BF_OVR_ERR_STAT_MASK ( 0x1 )
+#define BF_UND_ERR_STAT_MASK ( 0x1 )
+#define BF_FSYNC_ERR_STAT_MASK ( 0x1 )
+#define ERR_STAT_BF_OVR_ERR_STAT_SHIFT ( 0 )
+#define ERR_STAT_BF_UND_ERR_STAT_SHIFT ( 1 )
+#define ERR_STAT_BF_FSYNC_ERR_STAT_SHIFT ( 2 )
+#define ERR_STAT_BF_BF_OVR_ERR_STAT_MASK ( BF_OVR_ERR_STAT_MASK << ERR_STAT_BF_OVR_ERR_STAT_SHIFT )
+#define ERR_STAT_BF_BF_UND_ERR_STAT_MASK ( BF_UND_ERR_STAT_MASK << ERR_STAT_BF_UND_ERR_STAT_SHIFT )
+#define ERR_STAT_BF_BF_FSYNC_ERR_STAT_MASK ( BF_FSYNC_ERR_STAT_MASK << ERR_STAT_BF_FSYNC_ERR_STAT_SHIFT )
+
+#define PING_PONG_SEL_PING ( 0 )
+#define PING_PONG_SEL_PONG ( 1 )
+
+#endif /* _ICSS_pru_i2s_FW_H_ */
diff --git a/examples/pru_i2s/firmware/TDM4/linker.cmd b/examples/pru_i2s/firmware/TDM4/linker.cmd
new file mode 100644
index 000000000..b84523d29
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/linker.cmd
@@ -0,0 +1,88 @@
+/****************************************************************************/
+/* ICSSG_PRU.cmd */
+/* Copyright (c) 2025 Texas Instruments Incorporated */
+/* */
+/* Description: This file is a linker command file that can be used for */
+/* linking PRU programs built with the C compiler and */
+/* the resulting .out file on an pru device. */
+/****************************************************************************/
+
+/* -cr */ /* Link using C conventions */
+/* -stack 0x100 */
+
+/* Specify the System Memory Map */
+MEMORY
+{
+ PAGE 0:
+ PRU_IMEM : org = 0x00000000 len = 0x00004000 /* 16kB ICSSG_PRU Instruction RAM */
+
+ PAGE 1:
+
+ /* RAM */
+
+ PRU_DMEM_0_1_LOW : org = 0x00000000 len = 0x00001000 /* 4kB ICSSG Data RAM 0_1 for PRU*/
+ PRU_DMEM_0_1_HIGH : org = 0x00001000 len = 0x00001000 /* 4kB ICSSG Data RAM 0_1 for RTU*/
+ PRU_DMEM_1_0 : org = 0x00002000 len = 0x00002000 /* 8kB ICSSG Data RAM 1_0 */
+
+ PAGE 2:
+ PRU_SHAREDMEM : org = 0x00010000 len = 0x00010000 CREGISTER=28 /* 64kB Shared RAM */
+
+ /* Peripherals */
+
+ PRU_CFG : org = 0x00026000 len = 0x00000120 CREGISTER=4
+
+ RSVD0 : org = 0x00020000 len = 0x00001504 CREGISTER=0
+ RSVD1 : org = 0x48040000 len = 0x0000005C CREGISTER=1
+ RSVD2 : org = 0x4802A000 len = 0x000000D8 CREGISTER=2
+ RSVD3 : org = 0x00030000 len = 0x00000060 CREGISTER=3
+ RSVD5 : org = 0x48060000 len = 0x00000300 CREGISTER=5
+ RSVD6 : org = 0x48030000 len = 0x000001A4 CREGISTER=6
+ RSVD7 : org = 0x00028000 len = 0x00000038 CREGISTER=7
+ RSVD8 : org = 0x46000000 len = 0x00000100 CREGISTER=8
+ RSVD9 : org = 0x4A100000 len = 0x0000128C CREGISTER=9
+ RSVD10 : org = 0x48318000 len = 0x00000100 CREGISTER=10
+ RSVD11 : org = 0x48022000 len = 0x00000088 CREGISTER=11
+ RSVD12 : org = 0x48024000 len = 0x00000088 CREGISTER=12
+ RSVD13 : org = 0x48310000 len = 0x00000100 CREGISTER=13
+ RSVD14 : org = 0x481CC000 len = 0x000001E8 CREGISTER=14
+ RSVD15 : org = 0x481D0000 len = 0x000001E8 CREGISTER=15
+ RSVD16 : org = 0x481A0000 len = 0x000001A4 CREGISTER=16
+ RSVD17 : org = 0x4819C000 len = 0x000000D8 CREGISTER=17
+ RSVD18 : org = 0x48300000 len = 0x000002C4 CREGISTER=18
+ RSVD19 : org = 0x48302000 len = 0x000002C4 CREGISTER=19
+ RSVD20 : org = 0x48304000 len = 0x000002C4 CREGISTER=20
+ RSVD21 : org = 0x00032400 len = 0x00000100 CREGISTER=21
+ RSVD22 : org = 0x480C8000 len = 0x00000140 CREGISTER=22
+ RSVD23 : org = 0x480CA000 len = 0x00000880 CREGISTER=23
+ RSVD26 : org = 0x0002E000 len = 0x0000031C CREGISTER=26
+ RSVD27 : org = 0x00032000 len = 0x00000100 CREGISTER=27
+ RSVD29 : org = 0x49000000 len = 0x00001098 CREGISTER=29
+}
+
+/* Specify the sections allocation into memory */
+SECTIONS {
+ /* Forces _c_int00 to the start of PRU IRAM. Not necessary when loading
+ an ELF file, but useful when loading a binary */
+ /* .text:_c_int00* > 0x0, PAGE 0 */
+
+ /* .text > PRU_IMEM, PAGE 0 */
+ /* .stack > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .bss > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .cio > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .data > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .switch > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .sysmem > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .cinit > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .rodata > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .rofardata > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .farbss > PRU_DMEM_0_1_LOW, PAGE 1 */
+ /* .fardata > PRU_DMEM_0_1_LOW, PAGE 1 */
+
+ .text > PRU_IMEM, PAGE 0
+ .data > PRU_DMEM_0_1_LOW, PAGE 1
+ .fwRegs > 0x0, PAGE 1
+
+ .outSamps > PRU_DMEM_0_1_LOW, PAGE 1
+
+ .dbgBuf > PRU_SHAREDMEM, PAGE 2
+}
diff --git a/examples/pru_i2s/firmware/TDM4/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/example.projectspec b/examples/pru_i2s/firmware/TDM4/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/example.projectspec
new file mode 100644
index 000000000..5212861c8
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/example.projectspec
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/pru_i2s/firmware/TDM4/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/makefile b/examples/pru_i2s/firmware/TDM4/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/makefile
new file mode 100644
index 000000000..07568e5a9
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/makefile
@@ -0,0 +1,90 @@
+################################################################################
+# PRU I2S Firmware Makefile
+################################################################################
+# Required input arguments :
+# Build firmware for PRU I2S Use this input argument to include files from external paths
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+CG_TOOL_ROOT := $(CGT_TI_PRU_PATH)
+
+# Add inputs and outputs from these tool invocations to the build variables
+CMD_SRCS += \
+ linker.cmd \
+
+ASM_SRCS += \
+ pru_i2s_main.asm \
+ fw_regs.asm \
+
+OBJS += \
+ pru_i2s_main.obj \
+ fw_regs.obj \
+
+ASM_DEPS += \
+ pru_i2s_main.d \
+ fw_regs.d \
+
+OBJDIR := .
+
+FILES_PATH_common = \
+ .. \
+ ../../.. \
+ ../../../.. \
+ ../../../../.. \
+
+FILES_PATH := $(FILES_PATH_common)
+
+vpath %.asm $(FILES_PATH)
+vpath %.obj $(OBJDIR)
+vpath %.cmd $(FILES_PATH)
+
+
+# Add inputs and outputs from these tool invocations to the build variables
+EXE_OUTPUTS += \
+pru_i2s_tdm4_pru0_array_am261x-lp_icssm0-pru0_fw_ti-pru-cgt.out \
+
+EXE_OUTPUTS__QUOTED += \
+"pru_i2s_tdm4_pru0_array_am261x-lp_icssm0-pru0_fw_ti-pru-cgt.out" \
+
+BIN_OUTPUTS += \
+pru_i2s_tdm4_pru0_array_am261x-lp_icssm0-pru0_fw_ti-pru-cgt.hex \
+
+BIN_OUTPUTS__QUOTED += \
+"pru_i2s_tdm4_pru0_array_am261x-lp_icssm0-pru0_fw_ti-pru-cgt.hex" \
+
+# All Target
+all: $(OBJS) $(CMD_SRCS)
+ @$(MAKE) --no-print-directory -Onone "pru_i2s_tdm4_pru0_array_am261x-lp_icssm0-pru0_fw_ti-pru-cgt.out"
+
+# Each subdirectory must supply rules for building sources it contributes
+$(OBJDIR)/%.obj %.obj: %.asm
+ @echo 'Building file: "$^"'
+ @echo 'Invoking: PRU Compiler'
+ "$(CGT_TI_PRU_PATH)/bin/clpru" -DPRU0 -DSLICE0 -v4 --define=SOC_AM261X --define=PRU0 --define=I2S_TX --define=NUMBER_OF_TX_3 --define=I2S_TX_DETECT_UNDERFLOW --include_path="${CG_TOOL_ROOT}/include" --include_path="${MCU_PLUS_SDK_PATH}/source" --include_path="${OPEN_PRU_PATH}/source" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/include" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/TDM4" --define=_DEBUG_=1 -g --diag_warning=225 --diag_wrap=off --display_error_number --endian=little --preproc_with_compile --preproc_dependency="$(basename $( ${OPEN_PRU_PATH}/examples/pru_i2s/firmware/TDM4/pru_i2s_tdm4_pru0_array.h
+ -$(RM) pru_i2s_tdm4_pru0_array.h
+ -@echo ' '
+
+.PHONY: all clean
diff --git a/examples/pru_i2s/firmware/TDM4/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/makefile_projectspec b/examples/pru_i2s/firmware/TDM4/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/makefile_projectspec
new file mode 100644
index 000000000..4f378e28a
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt/makefile_projectspec
@@ -0,0 +1,20 @@
+#
+# Auto generated makefile
+#
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+
+PROFILE?=Release
+
+PROJECT_NAME=pru_i2s_tdm4_pru0_array_am261x-lp_icssm0-pru0_fw_ti-pru-cgt
+
+all:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE)
+
+clean:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) -ccs.clean
+
+export:
+ $(MKDIR) $(OPEN_PRU_PATH)/ccs_projects
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectCreate -ccs.projectSpec example.projectspec -ccs.overwrite full
diff --git a/examples/pru_i2s/firmware/TDM4/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/example.projectspec b/examples/pru_i2s/firmware/TDM4/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/example.projectspec
new file mode 100644
index 000000000..f433c0b6f
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/example.projectspec
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/pru_i2s/firmware/TDM4/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/makefile b/examples/pru_i2s/firmware/TDM4/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/makefile
new file mode 100644
index 000000000..a237b76aa
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/makefile
@@ -0,0 +1,90 @@
+################################################################################
+# PRU I2S Firmware Makefile
+################################################################################
+# Required input arguments :
+# Build firmware for PRU I2S Use this input argument to include files from external paths
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+CG_TOOL_ROOT := $(CGT_TI_PRU_PATH)
+
+# Add inputs and outputs from these tool invocations to the build variables
+CMD_SRCS += \
+ linker.cmd \
+
+ASM_SRCS += \
+ pru_i2s_main.asm \
+ fw_regs.asm \
+
+OBJS += \
+ pru_i2s_main.obj \
+ fw_regs.obj \
+
+ASM_DEPS += \
+ pru_i2s_main.d \
+ fw_regs.d \
+
+OBJDIR := .
+
+FILES_PATH_common = \
+ .. \
+ ../../.. \
+ ../../../.. \
+ ../../../../.. \
+
+FILES_PATH := $(FILES_PATH_common)
+
+vpath %.asm $(FILES_PATH)
+vpath %.obj $(OBJDIR)
+vpath %.cmd $(FILES_PATH)
+
+
+# Add inputs and outputs from these tool invocations to the build variables
+EXE_OUTPUTS += \
+pru_i2s_tdm4_pru0_array_am263x-cc_icssm0-pru0_fw_ti-pru-cgt.out \
+
+EXE_OUTPUTS__QUOTED += \
+"pru_i2s_tdm4_pru0_array_am263x-cc_icssm0-pru0_fw_ti-pru-cgt.out" \
+
+BIN_OUTPUTS += \
+pru_i2s_tdm4_pru0_array_am263x-cc_icssm0-pru0_fw_ti-pru-cgt.hex \
+
+BIN_OUTPUTS__QUOTED += \
+"pru_i2s_tdm4_pru0_array_am263x-cc_icssm0-pru0_fw_ti-pru-cgt.hex" \
+
+# All Target
+all: $(OBJS) $(CMD_SRCS)
+ @$(MAKE) --no-print-directory -Onone "pru_i2s_tdm4_pru0_array_am263x-cc_icssm0-pru0_fw_ti-pru-cgt.out"
+
+# Each subdirectory must supply rules for building sources it contributes
+$(OBJDIR)/%.obj %.obj: %.asm
+ @echo 'Building file: "$^"'
+ @echo 'Invoking: PRU Compiler'
+ "$(CGT_TI_PRU_PATH)/bin/clpru" -DPRU0 -DSLICE0 -v4 --define=SOC_AM263X --define=PRU0 --define=I2S_TX --define=NUMBER_OF_TX_3 --define=I2S_TX_DETECT_UNDERFLOW --include_path="${CG_TOOL_ROOT}/include" --include_path="${MCU_PLUS_SDK_PATH}/source" --include_path="${OPEN_PRU_PATH}/source" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/include" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/TDM4" --define=_DEBUG_=1 -g --diag_warning=225 --diag_wrap=off --display_error_number --endian=little --preproc_with_compile --preproc_dependency="$(basename $( ${OPEN_PRU_PATH}/examples/pru_i2s/firmware/TDM4/pru_i2s_tdm4_pru0_array.h
+ -$(RM) pru_i2s_tdm4_pru0_array.h
+ -@echo ' '
+
+.PHONY: all clean
diff --git a/examples/pru_i2s/firmware/TDM4/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/makefile_projectspec b/examples/pru_i2s/firmware/TDM4/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/makefile_projectspec
new file mode 100644
index 000000000..6e30761e9
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt/makefile_projectspec
@@ -0,0 +1,20 @@
+#
+# Auto generated makefile
+#
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+
+PROFILE?=Release
+
+PROJECT_NAME=pru_i2s_tdm4_pru0_array_am263x-cc_icssm0-pru0_fw_ti-pru-cgt
+
+all:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE)
+
+clean:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) -ccs.clean
+
+export:
+ $(MKDIR) $(OPEN_PRU_PATH)/ccs_projects
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectCreate -ccs.projectSpec example.projectspec -ccs.overwrite full
diff --git a/examples/pru_i2s/firmware/TDM4/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/example.projectspec b/examples/pru_i2s/firmware/TDM4/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/example.projectspec
new file mode 100644
index 000000000..03b4fa525
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/example.projectspec
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/pru_i2s/firmware/TDM4/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/makefile b/examples/pru_i2s/firmware/TDM4/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/makefile
new file mode 100644
index 000000000..28774afa4
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/makefile
@@ -0,0 +1,90 @@
+################################################################################
+# PRU I2S Firmware Makefile
+################################################################################
+# Required input arguments :
+# Build firmware for PRU I2S Use this input argument to include files from external paths
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+CG_TOOL_ROOT := $(CGT_TI_PRU_PATH)
+
+# Add inputs and outputs from these tool invocations to the build variables
+CMD_SRCS += \
+ linker.cmd \
+
+ASM_SRCS += \
+ pru_i2s_main.asm \
+ fw_regs.asm \
+
+OBJS += \
+ pru_i2s_main.obj \
+ fw_regs.obj \
+
+ASM_DEPS += \
+ pru_i2s_main.d \
+ fw_regs.d \
+
+OBJDIR := .
+
+FILES_PATH_common = \
+ .. \
+ ../../.. \
+ ../../../.. \
+ ../../../../.. \
+
+FILES_PATH := $(FILES_PATH_common)
+
+vpath %.asm $(FILES_PATH)
+vpath %.obj $(OBJDIR)
+vpath %.cmd $(FILES_PATH)
+
+
+# Add inputs and outputs from these tool invocations to the build variables
+EXE_OUTPUTS += \
+pru_i2s_tdm4_pru1_array_am261x-lp_icssm0-pru1_fw_ti-pru-cgt.out \
+
+EXE_OUTPUTS__QUOTED += \
+"pru_i2s_tdm4_pru1_array_am261x-lp_icssm0-pru1_fw_ti-pru-cgt.out" \
+
+BIN_OUTPUTS += \
+pru_i2s_tdm4_pru1_array_am261x-lp_icssm0-pru1_fw_ti-pru-cgt.hex \
+
+BIN_OUTPUTS__QUOTED += \
+"pru_i2s_tdm4_pru1_array_am261x-lp_icssm0-pru1_fw_ti-pru-cgt.hex" \
+
+# All Target
+all: $(OBJS) $(CMD_SRCS)
+ @$(MAKE) --no-print-directory -Onone "pru_i2s_tdm4_pru1_array_am261x-lp_icssm0-pru1_fw_ti-pru-cgt.out"
+
+# Each subdirectory must supply rules for building sources it contributes
+$(OBJDIR)/%.obj %.obj: %.asm
+ @echo 'Building file: "$^"'
+ @echo 'Invoking: PRU Compiler'
+ "$(CGT_TI_PRU_PATH)/bin/clpru" -DPRU1 -DSLICE1 -v4 --define=SOC_AM261X --define=PRU1 --define=I2S_RX --define=I2S_RX_DETECT_OVERFLOW --include_path="${CG_TOOL_ROOT}/include" --include_path="${MCU_PLUS_SDK_PATH}/source" --include_path="${OPEN_PRU_PATH}/source" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/include" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/TDM4" --define=_DEBUG_=1 -g --diag_warning=225 --diag_wrap=off --display_error_number --endian=little --preproc_with_compile --preproc_dependency="$(basename $( ${OPEN_PRU_PATH}/examples/pru_i2s/firmware/TDM4/pru_i2s_tdm4_pru1_array.h
+ -$(RM) pru_i2s_tdm4_pru1_array.h
+ -@echo ' '
+
+.PHONY: all clean
diff --git a/examples/pru_i2s/firmware/TDM4/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/makefile_projectspec b/examples/pru_i2s/firmware/TDM4/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/makefile_projectspec
new file mode 100644
index 000000000..5b38b87b5
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt/makefile_projectspec
@@ -0,0 +1,20 @@
+#
+# Auto generated makefile
+#
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+
+PROFILE?=Release
+
+PROJECT_NAME=pru_i2s_tdm4_pru1_array_am261x-lp_icssm0-pru1_fw_ti-pru-cgt
+
+all:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE)
+
+clean:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) -ccs.clean
+
+export:
+ $(MKDIR) $(OPEN_PRU_PATH)/ccs_projects
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectCreate -ccs.projectSpec example.projectspec -ccs.overwrite full
diff --git a/examples/pru_i2s/firmware/TDM4/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/example.projectspec b/examples/pru_i2s/firmware/TDM4/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/example.projectspec
new file mode 100644
index 000000000..624cfbe17
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/example.projectspec
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/pru_i2s/firmware/TDM4/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/makefile b/examples/pru_i2s/firmware/TDM4/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/makefile
new file mode 100644
index 000000000..9508b87f7
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/makefile
@@ -0,0 +1,90 @@
+################################################################################
+# PRU I2S Firmware Makefile
+################################################################################
+# Required input arguments :
+# Build firmware for PRU I2S Use this input argument to include files from external paths
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+CG_TOOL_ROOT := $(CGT_TI_PRU_PATH)
+
+# Add inputs and outputs from these tool invocations to the build variables
+CMD_SRCS += \
+ linker.cmd \
+
+ASM_SRCS += \
+ pru_i2s_main.asm \
+ fw_regs.asm \
+
+OBJS += \
+ pru_i2s_main.obj \
+ fw_regs.obj \
+
+ASM_DEPS += \
+ pru_i2s_main.d \
+ fw_regs.d \
+
+OBJDIR := .
+
+FILES_PATH_common = \
+ .. \
+ ../../.. \
+ ../../../.. \
+ ../../../../.. \
+
+FILES_PATH := $(FILES_PATH_common)
+
+vpath %.asm $(FILES_PATH)
+vpath %.obj $(OBJDIR)
+vpath %.cmd $(FILES_PATH)
+
+
+# Add inputs and outputs from these tool invocations to the build variables
+EXE_OUTPUTS += \
+pru_i2s_tdm4_pru1_array_am263x-cc_icssm0-pru1_fw_ti-pru-cgt.out \
+
+EXE_OUTPUTS__QUOTED += \
+"pru_i2s_tdm4_pru1_array_am263x-cc_icssm0-pru1_fw_ti-pru-cgt.out" \
+
+BIN_OUTPUTS += \
+pru_i2s_tdm4_pru1_array_am263x-cc_icssm0-pru1_fw_ti-pru-cgt.hex \
+
+BIN_OUTPUTS__QUOTED += \
+"pru_i2s_tdm4_pru1_array_am263x-cc_icssm0-pru1_fw_ti-pru-cgt.hex" \
+
+# All Target
+all: $(OBJS) $(CMD_SRCS)
+ @$(MAKE) --no-print-directory -Onone "pru_i2s_tdm4_pru1_array_am263x-cc_icssm0-pru1_fw_ti-pru-cgt.out"
+
+# Each subdirectory must supply rules for building sources it contributes
+$(OBJDIR)/%.obj %.obj: %.asm
+ @echo 'Building file: "$^"'
+ @echo 'Invoking: PRU Compiler'
+ "$(CGT_TI_PRU_PATH)/bin/clpru" -DPRU1 -DSLICE1 -v4 --define=SOC_AM263X --define=PRU1 --define=I2S_RX --define=I2S_RX_DETECT_OVERFLOW --include_path="${CG_TOOL_ROOT}/include" --include_path="${MCU_PLUS_SDK_PATH}/source" --include_path="${OPEN_PRU_PATH}/source" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/include" --include_path="${OPEN_PRU_PATH}/examples/pru_i2s/firmware/TDM4" --define=_DEBUG_=1 -g --diag_warning=225 --diag_wrap=off --display_error_number --endian=little --preproc_with_compile --preproc_dependency="$(basename $( ${OPEN_PRU_PATH}/examples/pru_i2s/firmware/TDM4/pru_i2s_tdm4_pru1_array.h
+ -$(RM) pru_i2s_tdm4_pru1_array.h
+ -@echo ' '
+
+.PHONY: all clean
diff --git a/examples/pru_i2s/firmware/TDM4/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/makefile_projectspec b/examples/pru_i2s/firmware/TDM4/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/makefile_projectspec
new file mode 100644
index 000000000..f2ba8448f
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt/makefile_projectspec
@@ -0,0 +1,20 @@
+#
+# Auto generated makefile
+#
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+
+PROFILE?=Release
+
+PROJECT_NAME=pru_i2s_tdm4_pru1_array_am263x-cc_icssm0-pru1_fw_ti-pru-cgt
+
+all:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE)
+
+clean:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) -ccs.clean
+
+export:
+ $(MKDIR) $(OPEN_PRU_PATH)/ccs_projects
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectCreate -ccs.projectSpec example.projectspec -ccs.overwrite full
diff --git a/examples/pru_i2s/firmware/TDM4/pru_i2s_interface.h b/examples/pru_i2s/firmware/TDM4/pru_i2s_interface.h
new file mode 100644
index 000000000..6a79d564d
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru_i2s_interface.h
@@ -0,0 +1,209 @@
+ ;
+ ; Copyright (C) 2024-2025 Texas Instruments Incorporated
+ ;
+ ; Redistribution and use in source and binary forms, with or without
+ ; modification, are permitted provided that the following conditions
+ ; are met:
+ ;
+ ; Redistributions of source code must retain the above copyright
+ ; notice, this list of conditions and the following disclaimer.
+ ;
+ ; Redistributions in binary form must reproduce the above copyright
+ ; notice, this list of conditions and the following disclaimer in the
+ ; documentation and/or other materials provided with the
+ ; distribution.
+ ;
+ ; Neither the name of Texas Instruments Incorporated nor the names of
+ ; its contributors may be used to endorse or promote products derived
+ ; from this software without specific prior written permission.
+ ;
+ ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ;
+
+ .if $isdefed("SOC_AM263X")
+ .if $isdefed("PRU0")
+I2S_INSTANCE_BCLK_PIN .set 6 ; PRG0_PRU0_GPOx
+I2S_INSTANCE_BCLK_PIN_POS .set 64 ; 2 << I2S_INSTANCE_BCLK_PIN
+
+I2S_INSTANCE_FS_PIN .set 1
+I2S_INSTANCE_FS_PIN_POS .set 2 ; 2 << I2S_INSTANCE_FS_PIN
+ .else
+I2S_INSTANCE_BCLK_PIN .set 0
+I2S_INSTANCE_BCLK_PIN_POS .set 1
+
+I2S_INSTANCE_FS_PIN .set 1
+I2S_INSTANCE_FS_PIN_POS .set 2
+ .endif
+
+ .if $isdefed("I2S_TX")
+ .if $isdefed("PRU0")
+I2S_INSTANCE1_SD_TX_PIN .set 2
+I2S_INSTANCE1_SD_TX_PIN_SHIFT .set I2S_INSTANCE1_SD_TX_PIN
+I2S_INSTANCE1_SD_TX_PIN_POS .set 4 ; 2 << I2S_INSTANCE1_SD_Tx_PIN
+
+I2S_INSTANCE2_SD_TX_PIN .set 3
+I2S_INSTANCE2_SD_TX_PIN_SHIFT .set I2S_INSTANCE2_SD_TX_PIN
+I2S_INSTANCE2_SD_TX_PIN_POS .set 8 ; 2 << I2S_INSTANCE2_SD_Tx_PIN
+
+I2S_INSTANCE3_SD_TX_PIN .set 5
+I2S_INSTANCE3_SD_TX_PIN_SHIFT .set I2S_INSTANCE3_SD_TX_PIN
+I2S_INSTANCE3_SD_TX_PIN_POS .set 32 ; 2 << I2S_INSTANCE3_SD_Tx_PIN
+ .else
+I2S_INSTANCE1_SD_TX_PIN .set 4
+I2S_INSTANCE1_SD_TX_PIN_SHIFT .set I2S_INSTANCE1_SD_TX_PIN
+I2S_INSTANCE1_SD_TX_PIN_POS .set 16 ; 2 << I2S_INSTANCE1_SD_Tx_PIN
+
+I2S_INSTANCE2_SD_TX_PIN .set 5
+I2S_INSTANCE2_SD_TX_PIN_SHIFT .set I2S_INSTANCE2_SD_TX_PIN
+I2S_INSTANCE2_SD_TX_PIN_POS .set 32 ; 2 << I2S_INSTANCE2_SD_Tx_PIN
+
+I2S_INSTANCE3_SD_TX_PIN .set 6
+I2S_INSTANCE3_SD_TX_PIN_SHIFT .set I2S_INSTANCE3_SD_TX_PIN
+I2S_INSTANCE3_SD_TX_PIN_POS .set 64 ; 2 << I2S_INSTANCE3_SD_Tx_PIN
+ .endif
+ .endif
+
+ .if $isdefed("I2S_RX")
+ .if $isdefed("PRU0")
+I2S_INSTANCE1_SD_RX_PIN .set 0
+I2S_INSTANCE1_SD_RX_PIN_SHIFT .set I2S_INSTANCE1_SD_RX_PIN
+I2S_INSTANCE1_SD_RX_PIN_POS .set 1 ; 2 << I2S_INSTANCE1_SD_Rx_PIN
+
+I2S_INSTANCE2_SD_RX_PIN .set 4
+I2S_INSTANCE2_SD_RX_PIN_SHIFT .set I2S_INSTANCE2_SD_RX_PIN
+I2S_INSTANCE2_SD_RX_PIN_POS .set 16 ; 2 << I2S_INSTANCE2_SD_Rx_PIN
+ .else
+I2S_INSTANCE1_SD_RX_PIN .set 2
+I2S_INSTANCE1_SD_RX_PIN_SHIFT .set I2S_INSTANCE1_SD_RX_PIN
+I2S_INSTANCE1_SD_RX_PIN_POS .set 4 ; 2 << I2S_INSTANCE1_SD_Rx_PIN
+
+I2S_INSTANCE2_SD_RX_PIN .set 3
+I2S_INSTANCE2_SD_RX_PIN_SHIFT .set I2S_INSTANCE2_SD_RX_PIN
+I2S_INSTANCE2_SD_RX_PIN_POS .set 8 ; 2 << I2S_INSTANCE2_SD_Rx_PIN
+ .endif
+ .endif
+ .endif ;SOC_AM263X
+ .if $isdefed("SOC_AM261X")
+ .if $isdefed("PRU0")
+; PRU0 Configuration
+I2S_INSTANCE_BCLK_PIN .set 5 ; PRU0 BCLK pin
+I2S_INSTANCE_BCLK_PIN_POS .set 32 ; 2 << 5
+
+I2S_INSTANCE_FS_PIN .set 6 ; PRU0 FSYNC pin
+I2S_INSTANCE_FS_PIN_POS .set 64 ; 2 << 6
+
+ .if $isdefed("I2S_TX")
+; PRU0 TX pins
+I2S_INSTANCE1_SD_TX_PIN .set 7 ; TX1
+I2S_INSTANCE1_SD_TX_PIN_SHIFT .set I2S_INSTANCE1_SD_TX_PIN
+I2S_INSTANCE1_SD_TX_PIN_POS .set 128 ; 2 << 7
+
+I2S_INSTANCE2_SD_TX_PIN .set 8 ; TX2
+I2S_INSTANCE2_SD_TX_PIN_SHIFT .set I2S_INSTANCE2_SD_TX_PIN
+I2S_INSTANCE2_SD_TX_PIN_POS .set 256 ; 2 << 8
+
+I2S_INSTANCE3_SD_TX_PIN .set 9 ; TX3
+I2S_INSTANCE3_SD_TX_PIN_SHIFT .set I2S_INSTANCE3_SD_TX_PIN
+I2S_INSTANCE3_SD_TX_PIN_POS .set 512 ; 2 << 9
+ .endif
+
+ .else
+; PRU1 Configuration
+I2S_INSTANCE_BCLK_PIN .set 5 ; PRU1 BCLK pin
+I2S_INSTANCE_BCLK_PIN_POS .set 32 ; 2 << 5
+
+I2S_INSTANCE_FS_PIN .set 9 ; PRU1 FSYNC pin
+I2S_INSTANCE_FS_PIN_POS .set 512 ; 2 << 9
+
+ .if $isdefed("I2S_RX")
+; PRU1 RX pins
+I2S_INSTANCE1_SD_RX_PIN .set 12 ; RX1
+I2S_INSTANCE1_SD_RX_PIN_SHIFT .set I2S_INSTANCE1_SD_RX_PIN
+I2S_INSTANCE1_SD_RX_PIN_POS .set 4096 ; 2 << 12
+
+I2S_INSTANCE2_SD_RX_PIN .set 13 ; RX2
+I2S_INSTANCE2_SD_RX_PIN_SHIFT .set I2S_INSTANCE2_SD_RX_PIN
+I2S_INSTANCE2_SD_RX_PIN_POS .set 8192 ; 2 << 13
+ .endif
+ .endif
+
+ .endif ;SOC_AM261X
+I2S_RXOVERFLOW_ERROR_POSITION .set 0
+I2S_TXUNDERFLOW_ERROR_POSITION .set 1
+I2S_FRAMESYNC_ERROR_POSITION .set 2
+
+;Address in FW Register space where TX PING address is stored
+I2S_TX_BUF_PING_ADD .set 4
+
+;Address in FW Register space where buffer size is stored. Buffer size is same for Tx and Rx. Buffer size is PING+PONG.
+I2S_PING_PONG_BUFSIZE_ADD .set 8
+
+;Address in FW Register space where RX PING address is stored
+I2S_RX_BUF_PING_ADD .set 0x14
+
+I2S_TX_BUF_PING_PONG_STAT_ADD .set 0x18
+
+I2S_RX_BUF_PING_PONG_STAT_ADD .set 0x19
+
+I2S_TX_INSTANCE_PING_PONG_STAT_ADD .set 0x1A
+
+I2S_RX_INSTANCE_PING_PONG_STAT_ADD .set 0x1B
+
+I2S_ERR_STAT_ADD .set 0x1C
+
+;Load 4 bytes from memory to register.
+BYTES_TO_LOAD .set 2 ; 4 bytes to load from memory for 4 bytes per channel configuration
+
+ .if $isdefed("PRU0")
+PRUx_CYCLE_CNT_REG_ADD .set 0x2200C; PRU0 cycle counter register address offset
+ .else
+PRUx_CYCLE_CNT_REG_ADD .set 0x2400C; PRU1 cycle counter register address offset
+ .endif
+;Number of samples per slot/channel
+I2S_SAMPLES_PER_CHANNEL .set 16
+I2S_SAMPLES_PER_CHANNEL_LESS_1 .set 15 ;I2S_SAMPLES_PER_CHANNEL-1
+TDM_CHANNELS .set 6 ; TDM channel slots used in TDM mode
+MAX_TDM_CHANNELS .set 6 ; Maximum TDM Slots (TDM4/TDM8)
+ .if $isdefed("PRU0")
+; Compile-time Host event for I2S Tx, pr0_pru_mst_intr[2]_intr_req
+TRIGGER_HOST_I2S_TX_EVT .set 18 ; 2+16
+; R31 event interface mapping, add pru_r31_vec_valid to system event number
+TRIGGER_HOST_I2S_TX_IRQ .set TRIGGER_HOST_I2S_TX_EVT + 16 ; 2+16+16 = 2+32 = 2 + 1<<5
+
+; Compile-time Host event for I2S Rx, pr0_pru_mst_intr[3]_intr_req
+TRIGGER_HOST_I2S_RX_EVT .set 19 ; 3+16
+; R31 event interface mapping, add pru_r31_vec_valid to system event number
+TRIGGER_HOST_I2S_RX_IRQ .set TRIGGER_HOST_I2S_RX_EVT + 16 ; 3+16+16 = 3+32 = 3 + 1<<5
+
+; Compile-time Host event for I2S Error, pr0_pru_mst_intr[4]_intr_req
+TRIGGER_HOST_I2S_ERR_EVT .set 20 ; 4+16
+; R31 event interface mapping, add pru_r31_vec_valid to system event number
+TRIGGER_HOST_I2S_ERR_IRQ .set TRIGGER_HOST_I2S_ERR_EVT + 16 ; 4+16+16 = 4+32 = 4 + 1<<5
+
+ .else
+; Compile-time Host event for I2S Tx, pr0_pru_mst_intr[2]_intr_req
+TRIGGER_HOST_I2S_TX_EVT .set 21 ; 5+16
+; R31 event interface mapping, add pru_r31_vec_valid to system event number
+TRIGGER_HOST_I2S_TX_IRQ .set TRIGGER_HOST_I2S_TX_EVT + 16 ; 2+16+16 = 2+32 = 2 + 1<<5
+
+; Compile-time Host event for I2S Rx, pr0_pru_mst_intr[3]_intr_req
+TRIGGER_HOST_I2S_RX_EVT .set 22 ; 6+16
+; R31 event interface mapping, add pru_r31_vec_valid to system event number
+TRIGGER_HOST_I2S_RX_IRQ .set TRIGGER_HOST_I2S_RX_EVT + 16 ; 3+16+16 = 3+32 = 3 + 1<<5
+
+; Compile-time Host event for I2S Error, pr0_pru_mst_intr[4]_intr_req
+TRIGGER_HOST_I2S_ERR_EVT .set 23 ; 7+16
+; R31 event interface mapping, add pru_r31_vec_valid to system event number
+TRIGGER_HOST_I2S_ERR_IRQ .set TRIGGER_HOST_I2S_ERR_EVT + 16 ; 4+16+16 = 4+32 = 4 + 1<<5
+
+ .endif
diff --git a/examples/pru_i2s/firmware/TDM4/pru_i2s_main.asm b/examples/pru_i2s/firmware/TDM4/pru_i2s_main.asm
new file mode 100644
index 000000000..5369ebeff
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru_i2s_main.asm
@@ -0,0 +1,517 @@
+ ;
+ ; Copyright (C) 2024-2025 Texas Instruments Incorporated
+ ;
+ ; Redistribution and use in source and binary forms, with or without
+ ; modification, are permitted provided that the following conditions
+ ; are met:
+ ;
+ ; Redistributions of source code must retain the above copyright
+ ; notice, this list of conditions and the following disclaimer.
+ ;
+ ; Redistributions in binary form must reproduce the above copyright
+ ; notice, this list of conditions and the following disclaimer in the
+ ; documentation and/or other materials provided with the
+ ; distribution.
+ ;
+ ; Neither the name of Texas Instruments Incorporated nor the names of
+ ; its contributors may be used to endorse or promote products derived
+ ; from this software without specific prior written permission.
+ ;
+ ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ; .sect ".text:main"
+ .clink
+ .global main
+
+ .include "pru_i2s_interface.h"
+ .include "pru_i2s_regs.h"
+main:
+;enable cyclecount
+ lbco &R0, c11, 0x00, 4
+ or R0, R0, (1<<3)
+ sbco &R0, c11, 0x00, 4
+ .if $isdefed("I2S_TX")
+ ;err_stat = err_stat >> 1. Remove the Rx Overflow error bit.
+ LSR err_stat, err_stat, 1
+ ;If there was an underflow/FrameSync Error, clearup thr Tx PingPong Buffer space
+ ;err_stat is already initialized during normal operation.
+ ; FS_ERROR UNDERFLOW_ERROR
+ ; 0 0 No Error
+ ; 0 1 Under Flow error
+ ; 1 0 FS Error
+ ; 1 1 Both errors
+ QBEQ CONTIUNE_INIT, err_stat, 0
+ ;If set, this means underflow has happened.
+ ;Below Initializations can be avoided but after power on, registers
+ ;may contain random addresses and may result in accessing illegal addresses.
+ LDI ch0_data_tx, 0x0
+ LDI scratchreg0, 0x0
+ LDI tx_buf_size, 0x0
+ LDI scratchreg0, I2S_TX_BUF_PING_ADD
+ LBBO &tx_ping_buffer_address, scratchreg0, 0, 4
+ LDI scratchreg0, I2S_PING_PONG_BUFSIZE_ADD
+ LBBO &tx_buf_size, scratchreg0, 0, 2
+ ADD tx_buffer_address_end, tx_ping_buffer_address, tx_buf_size
+ZERO_TX_PING_PONG:
+ SBBO &ch0_data_tx, tx_ping_buffer_address, 0, 4
+ ADD tx_ping_buffer_address, tx_ping_buffer_address, 0x4
+ QBGT ZERO_TX_PING_PONG, tx_ping_buffer_address, tx_buffer_address_end
+ .endif
+
+CONTIUNE_INIT:
+ ;Clear registers R0-R29. 4*30=120 bytes
+ ZERO &r0, 128
+ ; Load pin mask registers
+ .if $isdefed("I2S_TX")
+ LDI i2s_instance_fs_pin_pos, I2S_INSTANCE_FS_PIN_POS
+ .endif
+ .if $isdefed("I2S_RX")
+ LDI i2s_instance_fs_pin_pos, I2S_INSTANCE_FS_PIN_POS
+ LDI i2s_instance1_sd_rx_pin_pos, I2S_INSTANCE1_SD_RX_PIN_POS
+ LDI i2s_instance2_sd_rx_pin_pos, I2S_INSTANCE2_SD_RX_PIN_POS
+ .endif
+
+ LDI scratchreg2, I2S_TX_INSTANCE_PING_PONG_STAT_ADD
+ LDI scratchreg0, 0x2
+ ;Store 0x2 into TX_PING_PONG_STAT
+ SBBO &scratchreg0, scratchreg2, 0, 1
+
+ ;I2S_RX_INSTANCE_PING_PONG_STAT_ADD = I2S_TX_INSTANCE_PING_PONG_STAT_ADD+1
+ LDI scratchreg0, 0x1
+ ;Store 0x1 into RX_PING_PONG_STAT
+ SBBO &scratchreg0, scratchreg2, 1, 1
+
+ ;Start with Ping Buffer
+ LDI tx_buffer_num, 0x1
+ ;Start with Ping Buffer
+ LDI rx_buffer_num, 0x1
+ LDI tx_sd_counter, I2S_SAMPLES_PER_CHANNEL_LESS_1
+ LDI current_channel_no,1
+
+
+
+ .if $isdefed("I2S_TX")
+ ; these 3 pseudoinstructions are used for each additional output bit
+ ; move the bit of audio data we are going to output next to the LSb of r30_value
+ LSR r30_value, ch0_data_tx, tx_sd_counter
+ ;Remove other bits
+ AND r30_value, r30_value, 1
+ ;Move the LSb to the required position
+ LSL r30_value, r30_value, I2S_INSTANCE1_SD_TX_PIN_SHIFT
+ .endif
+ .if !$isdefed("I2S_TX")
+ .if $isdefed("I2S_RX")
+ ;Read the PING/PONG SEL address
+ LDI rx_ping_pong_sel_add, I2S_RX_BUF_PING_PONG_STAT_ADD
+ ;Read the PING/PONG STAT address
+ LDI rx_ping_pong_stat_add, I2S_RX_INSTANCE_PING_PONG_STAT_ADD
+ .endif
+ .endif
+
+ .if $isdefed("I2S_TX")
+ ;read the Tx buffer address provided by host. This should be in Shared memory
+ ; point to the PING audio buffer
+ LDI scratchreg0, I2S_TX_BUF_PING_ADD
+ LBBO &tx_buffer_address, scratchreg0, 0, 4
+ MOV tx_ping_buffer_address, tx_buffer_address
+ .endif
+
+ ;read the buffer size provided by host. buffer size is ping+pong
+ LDI scratchreg0, I2S_PING_PONG_BUFSIZE_ADD
+ LBBO &tx_buf_size, scratchreg0, 0, 2
+ ;Shift right by 1 to get PING/PONG size buffer size
+ LSR tx_buf_size, tx_buf_size, 1
+ .if $isdefed("I2S_RX")
+ MOV rx_buf_size, tx_buf_size
+ ;Rx buffer size is one less than PING/PONG buffer size
+ SUB rx_buf_size, rx_buf_size, 1
+
+ ;read the Rx buffer address provided by host
+ LDI scratchreg0, I2S_RX_BUF_PING_ADD
+ LBBO &rx_buffer_address, scratchreg0, 0, 4
+ MOV rx_ping_buffer_address, rx_buffer_address
+ LDI rx_sd_counter, I2S_SAMPLES_PER_CHANNEL -1
+ .endif
+
+ ;Initialize the end address of the Tx/Rx buffers
+ .if $isdefed("I2S_TX")
+ ADD tx_buffer_address_end, tx_buffer_address, tx_buf_size
+ .endif
+ .if $isdefed("I2S_RX")
+ ADD rx_buffer_address_end, rx_buffer_address, rx_buf_size
+ .endif
+ ;Initialize the PONG buffer addresses
+ .if $isdefed("I2S_TX")
+ MOV tx_pong_buffer_address, tx_buffer_address_end
+ .endif
+ .if $isdefed("I2S_RX")
+ MOV rx_pong_buffer_address, rx_buffer_address_end
+ ADD rx_pong_buffer_address, rx_pong_buffer_address, 1
+ .endif
+ .if $isdefed("I2S_TX")
+ ;Read the first bytes from Ping buffer
+ LBBO &ch0_data_tx, tx_buffer_address, 0, BYTES_TO_LOAD
+ ADD tx_buffer_address, tx_buffer_address, BYTES_TO_LOAD
+ ADD current_channel_no,current_channel_no,1
+ .endif
+
+INITIAL_STATE:
+ ; start iterating
+ ; wait until the input BCLK is low
+ ; then branch to wait for the rising edge
+ QBBS INITIAL_STATE, r31, I2S_INSTANCE_BCLK_PIN
+ ;Wait until there are 4 transitions of FS H-L-H-L-H
+INITIAL_STATE_FS:
+ ; start iterating
+ ; wait until the input FS is low
+ ; then branch to wait for the rising edge
+ QBBS INITIAL_STATE_FS, r31, I2S_INSTANCE_FS_PIN
+INITIAL_STATE_FS1:
+ ; wait until the input FS is high
+ QBBC INITIAL_STATE_FS1, r31, I2S_INSTANCE_FS_PIN
+INITIAL_STATE_FS2:
+ ; wait until the input FS is low
+ QBBS INITIAL_STATE_FS2, r31, I2S_INSTANCE_FS_PIN
+ qba START_SAMPLE
+BCLK_RISING_EDGE_LOW:
+ QBBC BCLK_RISING_EDGE_LOW, r31, I2S_INSTANCE_BCLK_PIN
+START_SAMPLE:
+ ; Read FS.
+ .if $isdefed("I2S_RX")
+ ;program delay betwen BCLK and Data
+ loop WAIT_FOR_RX_SAMPLE_ON_PIN, 10
+ add r0,r0,0
+WAIT_FOR_RX_SAMPLE_ON_PIN
+ .endif
+ AND fs_level, r31, i2s_instance_fs_pin_pos
+ .if $isdefed("I2S_RX")
+ ;Read I2S1 Rx data
+ AND ch0_rx_val_reg, r31, i2s_instance1_sd_rx_pin_pos
+ ;Read I2S2 Rx data
+ AND ch1_rx_val_reg, r31, i2s_instance2_sd_rx_pin_pos
+
+ ;Once the buffer is full, switch to new buffer
+ QBGT MANAGE_RX_BUFFERS, rx_buffer_address_end, rx_buffer_address
+ .endif
+ .if $isdefed("I2S_TX")
+ .if !$isdefed("I2S_RX")
+CONTINUE_TX_PROCESSING:
+ .endif
+ .endif
+ ; if fs_counter = 0x0, then do tx buffer management
+ QBEQ MANAGE_TX_BUFFERS, fs_counter, 0x0
+ .if $isdefed("SOC_AM64X")
+ ;if fs_counter = max(fs_counter) -1, then check FS before expected FS transition
+ QBEQ CHECK_FS_1, fs_counter, 0xE
+ ;if fs_counter = max(fs_counter), then check FS after expected FS transition
+ QBEQ CHECK_FS_2, fs_counter, 0xF
+ ;if fs_counter = max(fs_counter) -2, then load audio data
+ QBEQ LOAD_AUDIO_DATA, fs_counter, 0xD
+ .else
+ ;if fs_counter = max(fs_counter) -1, then check FS before expected FS transition
+ QBEQ CHECK_FS_1, fs_counter, (I2S_SAMPLES_PER_CHANNEL_LESS_1 - 1)
+ ;if fs_counter = max(fs_counter), then check FS after expected FS transition
+ QBEQ CHECK_FS_2, fs_counter, I2S_SAMPLES_PER_CHANNEL_LESS_1
+ ;if fs_counter = max(fs_counter) -2, then load audio data
+ QBEQ LOAD_AUDIO_DATA, fs_counter, (I2S_SAMPLES_PER_CHANNEL_LESS_1 - 2)
+ .endif
+ ;In case of Rx Only, Jump here after Sending Rx Notify to save PRU Cycles as we know fs_counter is 1.
+ .if !$isdefed("I2S_TX")
+ .if $isdefed("I2S_RX")
+CONTINUE_TX_PROCESSING:
+ .endif
+ .endif
+ ;else, increment fs_counter and wait for falling edge
+ ADD fs_counter, fs_counter, 0x1
+ .if $isdefed("I2S_TX_DETECT_UNDERFLOW")
+ ;Reset the variable here to save 1 cycle in BCLK LOW.
+ LDI do_tx_underflow_error_check, 0
+ .endif
+ ;if fs_counter = max(fs_counter)+1, then check FS after expected FS transition
+ QBGE CHECK_FS_3, fs_counter_1, 1
+ ;If not Jump
+ JMP BCLK_FALLING_EDGE_HIGH
+CHECK_FS_3:
+ LDI fs_counter_1, 0x0
+ LSR fs_level, fs_level, I2S_INSTANCE_FS_PIN
+ JMP BCLK_FALLING_EDGE_HIGH
+
+CHECK_FS_1:
+ ; if fs_counter = max(fs_counter) -1: Check for Early FS.
+ LSR fs_level, fs_level, I2S_INSTANCE_FS_PIN
+ ; increment fs_counter and wait for falling edge
+ ADD fs_counter, fs_counter, 0x1
+ JMP BCLK_FALLING_EDGE_HIGH
+
+CHECK_FS_2:
+ ; if fs_counter = max(fs_counter):
+ ;Increment counter.
+ ADD fs_counter_1, fs_counter_1, 0x1
+ ; reset fs_counter and wait for falling edge
+ LDI fs_counter, 0x0
+ JMP BCLK_FALLING_EDGE_HIGH
+
+LOAD_AUDIO_DATA:
+ .if $isdefed("I2S_TX")
+ .if $isdefed("SOC_AM64X")
+ ; load audio data from ping-pong buffers
+ ; note that scratch registers must be sequential
+ LBBO &scratchreg0, tx_buffer_address, 0, 4
+ ADD tx_buffer_address, tx_buffer_address, 0x4
+ .else
+ ; load audio data from ping-pong buffers
+ ; note that scratch registers must be sequential
+ LBBO &scratchreg0, tx_buffer_address, 0, BYTES_TO_LOAD
+ QBLT DATA_LOAD_DONE, current_channel_no, TDM_CHANNELS
+ ADD tx_buffer_address, tx_buffer_address, BYTES_TO_LOAD
+DATA_LOAD_DONE:
+ .endif
+ .endif
+ ; increment fs_counter and wait for falling edge
+ ADD fs_counter, fs_counter, 0x1
+ JMP BCLK_FALLING_EDGE_HIGH
+
+MANAGE_RX_BUFFERS:
+ .if $isdefed("I2S_RX")
+ ; if tx_buffer_address has reached the end of the buffer, point
+ ; to the beginning of the next buffer and notify the host core to
+ ; push fresh data to the buffer we just left.
+ ; if we are on buffer1, point to buffer2
+ QBEQ START_RX_BUFFER2, rx_buffer_num, 0x1
+
+ ; else, start buffer1
+ MOV rx_buffer_address, rx_ping_buffer_address
+ JMP RX_CONTINUE
+
+START_RX_BUFFER2:
+ MOV rx_buffer_address, rx_pong_buffer_address
+
+RX_CONTINUE:
+ ADD rx_buffer_address_end, rx_buffer_address, rx_buf_size
+ ; flip rx_buffer_num between 01_b and 01_b
+ XOR rx_buffer_num, rx_buffer_num, 0x1
+ SBBO &rx_buffer_num, rx_ping_pong_sel_add, 0, 1
+ ;set a condition to do Rx Overflow check
+ LDI do_rx_overflow_error_check, 1
+ ; notify the host
+ ;LDI R31.w0, TRIGGER_HOST_I2S_RX_IRQ
+ .endif ;I2S_RX
+ JMP CONTINUE_TX_PROCESSING
+
+MANAGE_TX_BUFFERS:
+ .if $isdefed("I2S_TX")
+ ; if tx_buffer_address has reached the end of the buffer, point
+ ; to the beginning of the next buffer and notify the host core to
+ ; push fresh data to the buffer we just left.
+ QBEQ START_NEW_BUFFER, tx_buffer_address, tx_buffer_address_end
+ .endif
+ ; increment fs_counter and wait for falling edge
+ ADD fs_counter, fs_counter, 0x1
+ JMP BCLK_FALLING_EDGE_HIGH
+
+START_NEW_BUFFER:
+ .if $isdefed("I2S_TX")
+ ; if we are on buffer1, point to buffer2
+ QBEQ START_BUFFER2, tx_buffer_num, 0x1
+
+ ; else, start buffer1
+ MOV tx_buffer_address, tx_ping_buffer_address
+ JMP CONTINUE
+
+START_BUFFER2:
+ MOV tx_buffer_address, tx_pong_buffer_address
+
+CONTINUE:
+ ADD tx_buffer_address_end, tx_buffer_address, tx_buf_size
+
+NOTIFY:
+ ; flip tx_buffer_num between 00_b and 01_b
+ XOR tx_buffer_num, tx_buffer_num, 0x1
+ LDI scratchreg2, I2S_TX_BUF_PING_PONG_STAT_ADD
+ SBBO &tx_buffer_num, scratchreg2, 0, 1
+ .if $isdefed("I2S_TX_DETECT_UNDERFLOW")
+ ;Read the Tx Ping Pong buffer stat from register address space
+ ;I2S_TX_INSTANCE_PING_PONG_STAT_ADD = I2S_TX_BUF_PING_PONG_STAT_ADD+2
+ LBBO &tx_ping_pong_stat, scratchreg2, 2, 1
+
+ ;If tx_buffer_num is 0, this means FW has already consumed PING buffer.
+ QBNE TX_PONG_BUF, tx_buffer_num, 0x0
+ ;Check if the PONG buffer has valid data
+ QBBC ERROR_HANDLING_UNDERFLOW, tx_ping_pong_stat, 1
+ ;If 1, this means PONG buffer has valid data. Clear the PING buffer status
+ CLR tx_ping_pong_stat, tx_ping_pong_stat, 0
+ JMP STORE_TX_PING_PONG_STAT
+
+TX_PONG_BUF:
+ ;Check if the PING buffer is full
+ QBBC ERROR_HANDLING_UNDERFLOW, tx_ping_pong_stat, 0
+ ;If 1, this means PING buffer has valid data. Clear the PONG buffer status
+ CLR tx_ping_pong_stat, tx_ping_pong_stat, 1
+
+STORE_TX_PING_PONG_STAT:
+ ;set a condition to perform some part of Tx Underflow in other half of BLCK
+ LDI do_tx_underflow_error_check, 1
+ ;SBBO &tx_ping_pong_stat, scratchreg2, 2, 1
+ .endif ;I2S_TX_DETECT_UNDERFLOW
+ ; notify the host
+ ;LDI R31.w0, TRIGGER_HOST_I2S_TX_IRQ
+ .endif ;I2S_TX
+ ; increment fs_counter and wait for falling edge
+ ADD fs_counter, fs_counter, 0x1
+
+BCLK_FALLING_EDGE_HIGH:
+
+ .if $isdefed("I2S_TX")
+ ; write to R30 as soon as we see the falling clock edge
+ MOV r30, r30_value
+ .endif
+WAIT_BCLK_REMAIN_HIGH:
+ QBBS WAIT_BCLK_REMAIN_HIGH, r31, I2S_INSTANCE_BCLK_PIN
+ .if $isdefed("I2S_TX")
+ .if $isdefed("I2S_TX_DETECT_UNDERFLOW")
+ QBNE CONTINUE_TX_PROCESS, do_tx_underflow_error_check, 0x1
+ ;Moved this to BCLK HIGH to save 1 cycle to meet I2S spec
+ ;LDI do_tx_underflow_error_check, 0
+ SBBO &tx_ping_pong_stat, scratchreg2, 2, 1
+ .endif ;I2S_TX_DETECT_UNDERFLOW
+ ; notify the host
+ LDI R31.w0, TRIGGER_HOST_I2S_TX_IRQ
+CONTINUE_TX_PROCESS:
+ .endif
+ .if $isdefed("I2S_RX")
+ .if $isdefed("I2S_RX_DETECT_OVERFLOW")
+ QBNE CONTINUE_RX_PROCESS, do_rx_overflow_error_check, 0x1
+ LDI do_rx_overflow_error_check, 0
+ ;Read the Rx Ping Pong buffer stat from register address space
+ LBBO &rx_ping_pong_stat, rx_ping_pong_stat_add, 0, 1
+ ;If rx_buffer_num is 0, this means FW has already filled PING buffer.
+ QBNE RX_PONG_BUF, rx_buffer_num, 0x0
+ ;Check if the PONG buffer is consumed by R5F. If consumed, bit 1 will be set to 0 by R5F, else it will be 1.
+ QBBS ERROR_HANDLING_OVERFLOW, rx_ping_pong_stat, 1
+ ;If 0, this means PONG buffer is consumed by R5F. SET the PING buffer status
+ SET rx_ping_pong_stat, rx_ping_pong_stat, 0
+ JMP STORE_RX_PING_PONG_STAT
+
+RX_PONG_BUF:
+ ;Check if the PING buffer is consumed by R5F. If consumed, bit 0 will be set to 0 by R5F, else it will be 1.
+ QBBS ERROR_HANDLING_OVERFLOW, rx_ping_pong_stat, 0
+ ;If 0, this means PING buffer is consumed by R5F. SET the PONG buffer status
+ SET rx_ping_pong_stat, rx_ping_pong_stat, 1
+STORE_RX_PING_PONG_STAT:
+ SBBO &rx_ping_pong_stat, rx_ping_pong_stat_add, 0, 1
+ .endif ;I2S_RX_DETECT_OVERFLOW
+ ; notify the host
+ LDI R31.w0, TRIGGER_HOST_I2S_RX_IRQ
+ .endif
+CONTINUE_RX_PROCESS:
+ .if $isdefed("I2S_TX")
+ ; if tx_sd_counter = 0, set to samples per channel 15/31
+ QBEQ RESET_SD_COUNTER, tx_sd_counter, 0
+ ; else, increment tx_sd_counter
+ SUB tx_sd_counter, tx_sd_counter, 0x1
+ .endif
+ JMP PREPARE_INPUT
+
+RESET_SD_COUNTER:
+ .if $isdefed("I2S_TX")
+ ; reset fs_counter and wait for falling edge
+ LDI tx_sd_counter, I2S_SAMPLES_PER_CHANNEL_LESS_1
+ QBGE TX_DATA_LOADING, current_channel_no, TDM_CHANNELS
+ LDI32 ch0_data_tx,0
+ QBA TX_DATA_LOADING_DONE
+TX_DATA_LOADING:
+ MOV ch0_data_tx, scratchreg0
+TX_DATA_LOADING_DONE:
+ QBNE NO_CH_RESET,current_channel_no, MAX_TDM_CHANNELS
+ LDI current_channel_no,1
+ QBA CH_UPDATE_DONE
+NO_CH_RESET:
+ ADD current_channel_no, current_channel_no, 1
+CH_UPDATE_DONE:
+ .endif
+
+PREPARE_INPUT:
+ ; these 3 pseudoinstructions are used for each additional output bit
+ ; move the bit of audio data we are going to output next to the LSb of r30_value
+ .if $isdefed("I2S_TX")
+ LSR r30_value, ch0_data_tx, tx_sd_counter
+ ;Remove other bits
+ AND r30_value, r30_value, 1
+ ;Move the LSb to the required position
+ LSL r30_value, r30_value, I2S_INSTANCE1_SD_TX_PIN_SHIFT
+ .endif
+ .if $isdefed("I2S_RX")
+ ; Receive Data
+ ; these 3 pseudoinstructions are used for each additional input bit
+ ; Skip for the first time since the first receive bit is valid after one bitclock after FS level change. See I2S spec.
+ ; Move the received bit to LSb position
+ LSR ch0_rx_val_reg, ch0_rx_val_reg, I2S_INSTANCE1_SD_RX_PIN_SHIFT
+ LSR ch1_rx_val_reg, ch1_rx_val_reg, I2S_INSTANCE2_SD_RX_PIN_SHIFT
+ ; Shift it to the required position
+ LSL ch0_rx_val_reg, ch0_rx_val_reg, rx_sd_counter
+ LSL ch1_rx_val_reg, ch1_rx_val_reg, rx_sd_counter
+ ; Append the bits of information to exisiting data
+ OR ch0_data_rx, ch0_data_rx, ch0_rx_val_reg
+ OR ch1_data_rx, ch1_data_rx, ch1_rx_val_reg
+ ; Once all the data is received, store the audio data.
+ QBEQ STORE_AUDIO_DATA, rx_sd_counter, 0
+
+SKIP:
+ SUB rx_sd_counter, rx_sd_counter, 1
+ .endif
+ JMP BCLK_RISING_EDGE_LOW
+
+STORE_AUDIO_DATA:
+ ;;FS Check if high or not
+ .if $isdefed("I2S_RX")
+ qbne NO_FS_CHECK,current_channel_no,MAX_TDM_CHANNELS
+ AND fs_level, r31, i2s_instance_fs_pin_pos
+ LSR fs_level, fs_level, I2S_INSTANCE_FS_PIN
+ qbeq ERROR_HANDLING_FS,fs_level,0
+NO_FS_CHECK:
+ .endif
+
+ .if $isdefed("I2S_RX")
+ ; store 32 bits of audio data per channel.
+ QBLT STORAGE_DONE,current_channel_no, TDM_CHANNELS
+ SBBO &ch0_data_rx, rx_buffer_address, 0, BYTES_TO_LOAD
+ ADD rx_buffer_address, rx_buffer_address, BYTES_TO_LOAD
+STORAGE_DONE:
+ ADD current_channel_no,current_channel_no,1
+ QBGE RX_CH_UPDATE_DONE,current_channel_no, MAX_TDM_CHANNELS
+ LDI current_channel_no,1
+RX_CH_UPDATE_DONE:
+
+ ; Reset ch0_rx_val_reg, ch1_rx_val_reg, ch0_data_rx, ch1_data_rx to 0. All these register must be continuous
+ ZERO &ch0_rx_val_reg, 16
+ LDI rx_sd_counter, I2S_SAMPLES_PER_CHANNEL_LESS_1
+ .endif
+ JMP BCLK_RISING_EDGE_LOW
+ERROR_HANDLING_OVERFLOW:
+ SET err_stat, err_stat, I2S_RXOVERFLOW_ERROR_POSITION
+ JMP ERROR_HANDLING_NOTIFY
+
+ERROR_HANDLING_UNDERFLOW:
+ SET err_stat, err_stat, I2S_TXUNDERFLOW_ERROR_POSITION
+ JMP ERROR_HANDLING_NOTIFY
+
+ERROR_HANDLING_FS:
+ SET err_stat, err_stat, I2S_FRAMESYNC_ERROR_POSITION
+
+ERROR_HANDLING_NOTIFY:
+ ;Load the ERR_STAT address into a scratch register
+ LDI scratchreg2, I2S_ERR_STAT_ADD
+ ;Store the error in to ERR_STAT
+ SBBO &err_stat, scratchreg2, 0, 1
+ ; notify the host
+ LDI R31.w0, TRIGGER_HOST_I2S_ERR_IRQ
+ JMP ||main||
diff --git a/examples/pru_i2s/firmware/TDM4/pru_i2s_regs.h b/examples/pru_i2s/firmware/TDM4/pru_i2s_regs.h
new file mode 100644
index 000000000..f6f2e973b
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru_i2s_regs.h
@@ -0,0 +1,114 @@
+ ;
+ ; Copyright (C) 2024-2025 Texas Instruments Incorporated
+ ;
+ ; Redistribution and use in source and binary forms, with or without
+ ; modification, are permitted provided that the following conditions
+ ; are met:
+ ;
+ ; Redistributions of source code must retain the above copyright
+ ; notice, this list of conditions and the following disclaimer.
+ ;
+ ; Redistributions in binary form must reproduce the above copyright
+ ; notice, this list of conditions and the following disclaimer in the
+ ; documentation and/or other materials provided with the
+ ; distribution.
+ ;
+ ; Neither the name of Texas Instruments Incorporated nor the names of
+ ; its contributors may be used to endorse or promote products derived
+ ; from this software without specific prior written permission.
+ ;
+ ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ ; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ ; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ ; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ;
+
+; define registers
+ .if $isdefed("I2S_PROFILE_FW")
+prux_cycle_cnt_0 .set r0
+prux_cycle_cnt_1 .set r1
+scratchreg_cycle_cnt .set r2
+prux_cycle_cnt .set r3
+cnt_buffer_address .set r4
+cnt_buffer_address_1 .set r5
+ .endif
+
+; Pin mask registers
+ .if !$isdefed("I2S_RX")
+i2s_instance_fs_pin_pos .set r11
+ .else
+i2s_instance_fs_pin_pos .set r7
+i2s_instance1_sd_rx_pin_pos .set r8
+i2s_instance2_sd_rx_pin_pos .set r9
+ .endif
+
+ .if !$isdefed("I2S_RX")
+;In case of Tx only, use some of the Rx registers.
+; tx_buffer_address keeps track of where we are in the audio buffer
+tx_buffer_address .set r0
+tx_buffer_address_end .set r1
+tx_ping_buffer_address .set r2
+tx_pong_buffer_address .set r3
+; ch0_data_tx is 16/32 bit audio sample
+ch0_data_tx .set r4
+ch1_data_tx .set r5
+ch2_data_tx .set r6
+r30_value .set r7
+r30_value_1 .set r8
+r30_value_2 .set r9
+ .endif
+
+tx_buf_size .set r10
+
+ .if $isdefed("I2S_RX")
+rx_ping_pong_sel_add .set r11
+rx_ping_pong_stat_add .set r12
+rx_buffer_address .set r13
+rx_buffer_address_end .set r14
+rx_ping_buffer_address .set r15
+rx_pong_buffer_address .set r16
+rx_buf_size .set r17
+;Read receive data
+ch0_rx_val_reg .set r18
+ch1_rx_val_reg .set r19
+;Accumulate receive data
+ch0_data_rx .set r20
+ch1_data_rx .set r21
+ .endif
+
+ ; fs_counter counts 16/32 clocks per frame sync
+ .asg r22.b0, fs_counter
+ ; fs_counter_1 used to compare FS after transition
+ .asg r22.b1, fs_counter_1
+ ; fs_num is frame sync number
+ ; 00_b (0) is L channel, 10_b (2) is R channel
+ .asg r22.b2, fs_num
+ .asg r28, fs_level
+
+scratchreg0 .set r23
+scratchreg1 .set r24
+scratchreg2 .set r25
+
+ .asg r26.b0, tx_sd_counter
+ .asg r26.b1, rx_sd_counter
+ ; this FW uses 2 buffers, tx_buffer_num says which buffer is current
+ .asg r26.b2, tx_buffer_num
+ .asg r26.b3, rx_buffer_num
+
+ .asg r27.b0, tx_ping_pong_stat
+ .asg r27.b1, rx_ping_pong_stat
+ .asg r27.b2, err_stat
+ .if $isdefed("I2S_RX")
+ .asg r27.b3, do_rx_overflow_error_check
+ .endif
+ .if $isdefed("I2S_TX")
+ .asg r27.b3, do_tx_underflow_error_check
+ .endif
+ .asg r29.b0 , current_channel_no
\ No newline at end of file
diff --git a/examples/pru_i2s/firmware/TDM4/pru_i2s_tdm4_pru0_array.h b/examples/pru_i2s/firmware/TDM4/pru_i2s_tdm4_pru0_array.h
new file mode 100644
index 000000000..43d2025f1
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru_i2s_tdm4_pru0_array.h
@@ -0,0 +1,159 @@
+const uint32_t pru_prupru_i2s0_image_0_0[] = {
+0x91002b80,
+0x1308e0e0,
+0x81002b80,
+0x0b015b5b,
+0x51005b0c,
+0x240000e4,
+0x240000f7,
+0x240000ea,
+0x240004f7,
+0xf1003782,
+0x240008f7,
+0xf100178a,
+0x00eae2e1,
+0xe1002284,
+0x0104e2e2,
+0x66e1e2fe,
+0x2effbf80,
+0x240002eb,
+0x24001af9,
+0x240002f7,
+0xe1001917,
+0x240001f7,
+0xe1011917,
+0x2400015a,
+0x2400017a,
+0x24000f1a,
+0x2400011d,
+0x0a1ae4e7,
+0x1101e7e7,
+0x0902e7e7,
+0x240004f7,
+0xf1003780,
+0x10e0e0e2,
+0x240008f7,
+0xf100178a,
+0x0b01eaea,
+0x00eae0e1,
+0x10e1e1e3,
+0xf1000084,
+0x0102e0e0,
+0x01011d1d,
+0xd106ff00,
+0xd101ff00,
+0xc901ff00,
+0xd101ff00,
+0x79000002,
+0xc906ff00,
+0x10ebfffc,
+0x51001617,
+0x510e160a,
+0x510f160c,
+0x510d160e,
+0x01011616,
+0x2400007b,
+0x71013602,
+0x21005b00,
+0x24000036,
+0x0b01fcfc,
+0x21005b00,
+0x0b01fcfc,
+0x01011616,
+0x21005b00,
+0x01013636,
+0x24000016,
+0x21005b00,
+0xf1000097,
+0x49061d02,
+0x0102e0e0,
+0x01011616,
+0x21005b00,
+0x21003000,
+0x50e1e003,
+0x01011616,
+0x21005b00,
+0x51015a03,
+0x10e2e2e0,
+0x21004e00,
+0x10e3e3e0,
+0x00eae0e1,
+0x15015a5a,
+0x240018f9,
+0xe100195a,
+0xf102191b,
+0x69005a04,
+0xc9011b20,
+0x1d001b1b,
+0x21005900,
+0xc9001b1d,
+0x1d011b1b,
+0x2400017b,
+0x01011616,
+0x10e7e7fe,
+0xd106ff00,
+0x69017b03,
+0xe102191b,
+0x2400229f,
+0x51001a03,
+0x05011a1a,
+0x21006d00,
+0x24000f1a,
+0x71061d04,
+0x240000c4,
+0x24000084,
+0x79000002,
+0x10f7f7e4,
+0x69061d03,
+0x2400011d,
+0x79000002,
+0x01011d1d,
+0x0a1ae4e7,
+0x1101e7e7,
+0x0902e7e7,
+0x21002e00,
+0x21002e00,
+0x1f005b5b,
+0x21007700,
+0x1f015b5b,
+0x21007700,
+0x1f025b5b,
+0x24001cf9,
+0xe100195b,
+0x2400249f,
+0x21000000};
+
+const uint8_t pru_prupru_i2s0_image_0_1[] = {
+0x03,
+0x00,
+0x30,
+0x20,
+0x00,
+0x00,
+0x01,
+0x00,
+0x08,
+0x01,
+0x12,
+0x13,
+0x14,
+0x06,
+0x01,
+0x02,
+0x03,
+0x05,
+0x00,
+0x04,
+0x00,
+0x01,
+0x01,
+0x00,
+0x00,
+0x00,
+0x02,
+0x01,
+0x00,
+0x00,
+0x00,
+0x00};
+
diff --git a/examples/pru_i2s/firmware/TDM4/pru_i2s_tdm4_pru1_array.h b/examples/pru_i2s/firmware/TDM4/pru_i2s_tdm4_pru1_array.h
new file mode 100644
index 000000000..e9502160e
--- /dev/null
+++ b/examples/pru_i2s/firmware/TDM4/pru_i2s_tdm4_pru1_array.h
@@ -0,0 +1,152 @@
+const uint32_t pru_prupru_i2s1_image_0_0[] = {
+0x91002b80,
+0x1308e0e0,
+0x81002b80,
+0x2effbf80,
+0x240002e7,
+0x240004e8,
+0x240008e9,
+0x24001af9,
+0x240002f7,
+0xe1001917,
+0x240001f7,
+0xe1011917,
+0x2400015a,
+0x2400017a,
+0x24000f1a,
+0x2400011d,
+0x240019eb,
+0x24001bec,
+0x240008f7,
+0xf100178a,
+0x0b01eaea,
+0x10eaeaf1,
+0x0501f1f1,
+0x240014f7,
+0xf100378d,
+0x10ededef,
+0x24000f3a,
+0x00f1edee,
+0x10eeeef0,
+0x0101f0f0,
+0xd100ff00,
+0xd101ff00,
+0xc901ff00,
+0xd101ff00,
+0x79000002,
+0xc900ff00,
+0x31090002,
+0x0100e0e0,
+0x10e7fffc,
+0x10e8fff2,
+0x10e9fff3,
+0x60edee13,
+0x5100161b,
+0x510e1609,
+0x510f160b,
+0x510d160d,
+0x01011616,
+0x71013602,
+0x21004800,
+0x24000036,
+0x0b01fcfc,
+0x21004800,
+0x0b01fcfc,
+0x01011616,
+0x21004800,
+0x01013636,
+0x24000016,
+0x21004800,
+0x01011616,
+0x21004800,
+0x51017a03,
+0x10efefed,
+0x21004000,
+0x10f0f0ed,
+0x00f1edee,
+0x15017a7a,
+0xe1000b7a,
+0x2400017b,
+0x21002e00,
+0x01011616,
+0x21004800,
+0x01011616,
+0xd100ff00,
+0x69017b0b,
+0x2400007b,
+0xf1000c3b,
+0x69007a04,
+0xd1013b1e,
+0x1f003b3b,
+0x21005200,
+0xd1003b1b,
+0x1f013b3b,
+0xe1000c3b,
+0x2400269f,
+0x21005500,
+0x0b02f2f2,
+0x0b03f3f3,
+0x083af2f2,
+0x083af3f3,
+0x12f2f4f4,
+0x12f3f5f5,
+0x51003a03,
+0x05013a3a,
+0x21002300,
+0x69061d04,
+0x10e7fffc,
+0x0b01fcfc,
+0x5100fc0e,
+0x49061d03,
+0xe1000d94,
+0x0102eded,
+0x01011d1d,
+0x71061d02,
+0x2400011d,
+0x2eff8792,
+0x24000f3a,
+0x21002300,
+0x1f005b5b,
+0x21007000,
+0x1f015b5b,
+0x21007000,
+0x1f025b5b,
+0x24001cf9,
+0xe100195b,
+0x2400279f,
+0x21000000};
+
+const uint8_t pru_prupru_i2s1_image_0_1[] = {
+0x00,
+0x02,
+0x30,
+0x20,
+0x00,
+0x02,
+0x01,
+0x00,
+0x00,
+0x01,
+0x15,
+0x16,
+0x17,
+0x00,
+0x01,
+0x04,
+0x05,
+0x06,
+0x02,
+0x03,
+0x00,
+0x03,
+0x01,
+0x00,
+0x00,
+0x00,
+0x02,
+0x01,
+0x00,
+0x00,
+0x00,
+0x00};
+
diff --git a/examples/pru_i2s/images/block_diagram_am261x.jpg b/examples/pru_i2s/images/block_diagram_am261x.jpg
new file mode 100644
index 000000000..842f0bb8c
Binary files /dev/null and b/examples/pru_i2s/images/block_diagram_am261x.jpg differ
diff --git a/examples/pru_i2s/images/block_diagram_am263x.png b/examples/pru_i2s/images/block_diagram_am263x.png
new file mode 100644
index 000000000..1432325d8
Binary files /dev/null and b/examples/pru_i2s/images/block_diagram_am263x.png differ
diff --git a/examples/pru_i2s/images/firmware_flow_rx.jpg b/examples/pru_i2s/images/firmware_flow_rx.jpg
new file mode 100644
index 000000000..d01d5f6c1
Binary files /dev/null and b/examples/pru_i2s/images/firmware_flow_rx.jpg differ
diff --git a/examples/pru_i2s/images/firmware_flow_tx.jpg b/examples/pru_i2s/images/firmware_flow_tx.jpg
new file mode 100644
index 000000000..780780cf5
Binary files /dev/null and b/examples/pru_i2s/images/firmware_flow_tx.jpg differ
diff --git a/examples/pru_i2s/images/pcm1.png b/examples/pru_i2s/images/pcm1.png
new file mode 100644
index 000000000..ea78a1286
Binary files /dev/null and b/examples/pru_i2s/images/pcm1.png differ
diff --git a/examples/pru_i2s/images/pcm2.png b/examples/pru_i2s/images/pcm2.png
new file mode 100644
index 000000000..b05ab0fe9
Binary files /dev/null and b/examples/pru_i2s/images/pcm2.png differ
diff --git a/examples/pru_i2s/images/pcm_channel_config.png b/examples/pru_i2s/images/pcm_channel_config.png
new file mode 100644
index 000000000..667db70de
Binary files /dev/null and b/examples/pru_i2s/images/pcm_channel_config.png differ
diff --git a/examples/pru_i2s/images/pcm_clock_signals.png b/examples/pru_i2s/images/pcm_clock_signals.png
new file mode 100644
index 000000000..9fbc5fc1b
Binary files /dev/null and b/examples/pru_i2s/images/pcm_clock_signals.png differ
diff --git a/examples/pru_i2s/images/pru_i2s_rx_arch.png b/examples/pru_i2s/images/pru_i2s_rx_arch.png
new file mode 100644
index 000000000..6b8077e11
Binary files /dev/null and b/examples/pru_i2s/images/pru_i2s_rx_arch.png differ
diff --git a/examples/pru_i2s/images/pru_i2s_tx_arch.png b/examples/pru_i2s/images/pru_i2s_tx_arch.png
new file mode 100644
index 000000000..38b1c3ecd
Binary files /dev/null and b/examples/pru_i2s/images/pru_i2s_tx_arch.png differ
diff --git a/examples/pru_i2s/images/rx_buffer_capture.png b/examples/pru_i2s/images/rx_buffer_capture.png
new file mode 100644
index 000000000..010817c34
Binary files /dev/null and b/examples/pru_i2s/images/rx_buffer_capture.png differ
diff --git a/examples/pru_i2s/images/setup_am261x.png b/examples/pru_i2s/images/setup_am261x.png
new file mode 100644
index 000000000..398165b0f
Binary files /dev/null and b/examples/pru_i2s/images/setup_am261x.png differ
diff --git a/examples/pru_i2s/images/setup_am263x.png b/examples/pru_i2s/images/setup_am263x.png
new file mode 100644
index 000000000..10b0c04b7
Binary files /dev/null and b/examples/pru_i2s/images/setup_am263x.png differ
diff --git a/examples/pru_i2s/include/pru_i2s_config.h b/examples/pru_i2s/include/pru_i2s_config.h
new file mode 100644
index 000000000..04e5248e0
--- /dev/null
+++ b/examples/pru_i2s/include/pru_i2s_config.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2024-2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file pru_i2s_config.h
+ *
+ * \brief PRU I2S Configuration Header
+ *
+ * This file contains user-editable configuration parameters for PRU I2S driver.
+ * Applications can modify this file to configure:
+ * - ICSS instance (ICSSM0 or ICSSM1)
+ * - PRU core selection (PRU0 or PRU1)
+ * - I2S/TDM mode
+ * - Number of Tx/Rx channels
+ * - Bits per slot
+ * - Sampling frequency
+ */
+
+#ifndef PRU_I2S_CONFIG_H_
+#define PRU_I2S_CONFIG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+
+/* =========================== Configuration Section =========================== */
+
+/**
+ * \brief PRU I2S Configuration Structure
+ *
+ * This structure defines the configuration for a PRU I2S instance.
+ * Applications should create instances of this structure to configure each PRU core.
+ */
+typedef struct {
+ /* ICSS and PRU Core Selection */
+ uint8_t icssInstId; /**< ICSS instance: 0=ICSSM0, 1=ICSSM1 */
+ uint8_t pruInstId; /**< PRU core: PRUICSS_PRU0 or PRUICSS_PRU1 */
+
+ /* I2S/TDM Configuration (optional - can be auto-detected from firmware) */
+ uint8_t numTxI2s; /**< Number of Tx I2S channels (0 = auto-detect from firmware) */
+ uint8_t numRxI2s; /**< Number of Rx I2S channels (0 = auto-detect from firmware) */
+ uint8_t sampFreq; /**< Sampling frequency in kHz (0 = auto-detect from firmware) */
+ uint8_t bitsPerSlot; /**< Bits per I2S slot (0 = auto-detect from firmware) */
+
+} PRUI2S_UserConfig;
+
+/* =========================== Example Configurations =========================== */
+
+/*
+ * Example 1: AM261x LaunchPad - ICSSM1 PRU0 for Tx
+ * - Uses ICSSM1 (icssInstId = 1)
+ * - Uses PRU0 (pruInstId = PRUICSS_PRU0)
+ * - Auto-detects I2S parameters from firmware
+ */
+#define PRUI2S_CONFIG_AM261X_LP_PRU0 \
+{ \
+ .icssInstId = 1, \
+ .pruInstId = PRUICSS_PRU0, \
+ .numTxI2s = 0, \
+ .numRxI2s = 0, \
+ .sampFreq = 0, \
+ .bitsPerSlot = 0, \
+}
+
+/*
+ * Example 2: AM261x LaunchPad - ICSSM1 PRU1 for Rx
+ * - Uses ICSSM1 (icssInstId = 1)
+ * - Uses PRU1 (pruInstId = PRUICSS_PRU1)
+ * - Auto-detects I2S parameters from firmware
+ */
+#define PRUI2S_CONFIG_AM261X_LP_PRU1 \
+{ \
+ .icssInstId = 1, \
+ .pruInstId = PRUICSS_PRU1, \
+ .numTxI2s = 0, \
+ .numRxI2s = 0, \
+ .sampFreq = 0, \
+ .bitsPerSlot = 0, \
+}
+
+/*
+ * Example 3: AM263x Control Card - ICSSM0 PRU0 for Tx and Rx
+ * - Uses ICSSM0 (icssInstId = 0)
+ * - Uses PRU0 (pruInstId = PRUICSS_PRU0)
+ * - Auto-detects I2S parameters from firmware
+ */
+#define PRUI2S_CONFIG_AM263X_CC_PRU0 \
+{ \
+ .icssInstId = 0, \
+ .pruInstId = PRUICSS_PRU0, \
+ .numTxI2s = 0, \
+ .numRxI2s = 0, \
+ .sampFreq = 0, \
+ .bitsPerSlot = 0, \
+}
+
+/*
+ * Example 4: AM263x Control Card - ICSSM0 PRU1 for Tx and Rx
+ * - Uses ICSSM0 (icssInstId = 0)
+ * - Uses PRU1 (pruInstId = PRUICSS_PRU1)
+ * - Auto-detects I2S parameters from firmware
+ */
+#define PRUI2S_CONFIG_AM263X_CC_PRU1 \
+{ \
+ .icssInstId = 0, \
+ .pruInstId = PRUICSS_PRU1, \
+ .numTxI2s = 0, \
+ .numRxI2s = 0, \
+ .sampFreq = 0, \
+ .bitsPerSlot = 0, \
+}
+
+/* =========================== Default Configuration Selection =========================== */
+
+/*
+ * Define the default configuration for your application.
+ * Uncomment and modify based on your hardware platform.
+ */
+#ifdef SOC_AM261X
+ /* AM261x uses ICSSM1 */
+ #define PRUI2S_USER_CONFIG_PRU0 PRUI2S_CONFIG_AM261X_LP_PRU0
+ #define PRUI2S_USER_CONFIG_PRU1 PRUI2S_CONFIG_AM261X_LP_PRU1
+#else
+ /* AM263x uses ICSSM0 */
+ #define PRUI2S_USER_CONFIG_PRU0 PRUI2S_CONFIG_AM263X_CC_PRU0
+ #define PRUI2S_USER_CONFIG_PRU1 PRUI2S_CONFIG_AM263X_CC_PRU1
+#endif
+
+/* =========================== Function Prototypes =========================== */
+
+/**
+ * \brief Initialize PRU I2S driver with user configuration
+ *
+ * This function should be called by the application to initialize the PRU I2S driver
+ * with the user-specified configuration. It must be called before PRUI2S_init().
+ *
+ * NOTE: The actual PRUI2S_setUserConfig() function is declared in pru_i2s_drv.h
+ * This header provides the PRUI2S_UserConfig structure definition and example configurations.
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PRU_I2S_CONFIG_H_ */
diff --git a/examples/pru_i2s/include/pru_i2s_drv.h b/examples/pru_i2s/include/pru_i2s_drv.h
new file mode 100644
index 000000000..f21231c65
--- /dev/null
+++ b/examples/pru_i2s/include/pru_i2s_drv.h
@@ -0,0 +1,710 @@
+/*
+ * Copyright (C) 2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PRU_I2S_DRV_H_
+#define PRU_I2S_DRV_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "TDM4/icss_pru_i2s_fw.h"
+/* Number of ICSS instances */
+#define PRUI2S_NUM_ICSS_INST ( 2 )
+/* Number of PRU instances per ICSS */
+#define PRUI2S_NUM_PRU_INST_PER_ICSS ( 2 )
+
+/* Maximum number of PRU I2S instances */
+#define PRU_I2S_MAX_NUM_INST ( PRUI2S_NUM_ICSS_INST * PRUI2S_NUM_PRU_INST_PER_ICSS )
+
+/* Default interrupt priorities.
+ VIM: 0(highest)..15(lowest). */
+#define PRUI2S_VIM_PRI_HIGHEST ( 0U )
+#define PRUI2S_VIM_PRI_LOWEST ( 15U )
+#define DEF_I2S_INTR_PRI ( PRUI2S_VIM_PRI_HIGHEST ) /* I2S */
+#define DEF_I2S_ERR_INTR_PRI ( PRUI2S_VIM_PRI_HIGHEST ) /* I2S error */
+
+/* Maximum VIM interrupt priority value */
+#define MAX_VIM_INTR_PRI_VAL ( PRUI2S_VIM_PRI_LOWEST )
+
+/* PRU GP Mux Select */
+#define PRUICSS_G_MUX_EN ( PRUICSS_SA_MUX_MODE_DEFAULT ) /* ICSSG_SA_MX_REG:G_MUX_EN */
+
+/* Number INTC system events per PRU */
+#define PRUI2S_PRUICSS_INTC_NUM_SYSEVT_PER_PRU \
+ ( 3 )
+
+/* PRU INTC system event indices */
+#define PRUI2S_PRU_INTC_SYSEVT0_IDX ( 0 ) /* I2S Tx system event index */
+#define PRUI2S_PRU_INTC_SYSEVT1_IDX ( 1 ) /* I2S Rx system event index */
+#define PRUI2S_PRU_INTC_SYSEVT2_IDX ( 2 ) /* I2S error system event index */
+
+/* Number INTC channels per PRU */
+#define PRUI2S_PRUICSS_INTC_NUM_CHANNELS_PER_PRU \
+ ( 3 )
+
+/* PRU-ARM Interrupt Events for INTC system event range (16-31)
+ Used for validating system event numbers in INTC configuration */
+#define PRU_ARM_EVENT00 16 /* Lowest PRU-ARM event number */
+#define PRU_ARM_EVENT15 31 /* Highest PRU-ARM event number */
+
+/* Support number of bits per I2S slot */
+#define PRUI2S_BITS_PER_SLOT_16 ( 16 ) /* 16 bits per slot */
+#define PRUI2S_BITS_PER_SLOT_32 ( 32 ) /* 32 bits per slot */
+
+#define PRUI2S_MAX_PRU_PIN_NUM ( 19 ) /* PRU maximum pin number */
+
+/* NOTE: All GPIO and pinmux configuration is now handled by SysConfig.
+ No hardcoded PAD or GPIO configuration is needed in the driver. */
+
+/* Return status codes */
+#define PRUI2S_DRV_SOK ( 0 ) /* OK */
+#define PRUI2S_DRV_SERR_INV_PRMS ( -1 ) /* Invalid function parameters */
+#define PRUI2S_DRV_SERR_INIT ( -2 ) /* Initialization error */
+#define PRUI2S_DRV_SERR_INIT_FWIMG ( -3 ) /* Initialization error, missing FW image */
+#define PRUI2S_DRV_SERR_PRU_EN ( -4 ) /* PRU core enable error */
+#define PRUI2S_DRV_SERR_CLOSE ( -5 ) /* Close error */
+#define PRUI2S_DRV_SERR_CLR_INT ( -6 ) /* INTC clear event error */
+
+/* Number of PRU I2S configurations */
+#define PRU_I2S_NUM_CONFIG ( 2 )
+
+/* Number of PRU I2S PRU images (firmware images) */
+#define PRU_I2S_NUM_PRU_IMAGE ( 2 )
+
+/* Maximum number of TX I2S */
+#define PRUI2S_MAX_TX_I2S ( 3 )
+/* Maximum number of RX I2S */
+#define PRUI2S_MAX_RX_I2S ( 2 )
+/* Maximum of TX & RX I2S */
+#if (PRUI2S_MAX_TX_I2S < PRUI2S_MAX_RX_I2S)
+#define PRUI2S_MAX_I2S ( PRUI2S_MAX_RX_I2S )
+#else
+#define PRUI2S_MAX_I2S ( PRUI2S_MAX_TX_I2S )
+#endif
+
+/* Interrupt types */
+#define INTR_TYPE_I2S_TX ( 0 )
+#define INTR_TYPE_I2S_RX ( 1 )
+#define INTR_TYPE_I2S_ERR ( 2 )
+
+/* Error status/mask bit-field bit locations */
+#define I2S_ERR_OVR_BN ( 0 ) /* Rx overflow error bit number */
+#define I2S_ERR_UND_BN ( 1 ) /* Tx underflow error bit number */
+#define I2S_ERR_FSYNC_BN ( 2 ) /* Frame sync error bit number */
+
+/* PRU I2S handle returned by open function */
+typedef void *PRUI2S_Handle;
+
+/* Callback function */
+typedef void (*PRUI2S_CallbackFxn) (PRUI2S_Handle handle);
+
+/* IO Buffer for Write/Read */
+typedef struct PRUI2S_IoBuf_s {
+ void *ioBufAddr; /* Interleaved buffer: Ch0 L, Ch1 L, ..., ChM L, Ch0 R, Ch1 R, ..., ChM R. */
+} PRUI2S_IoBuf;
+
+/* Conversion IO Buffer for Write/Read with conversion */
+typedef struct PRUI2S_IoBufC_s {
+ void *ioBufLAddr[PRUI2S_MAX_I2S]; /* Left channel buffers */
+ void *ioBufRAddr[PRUI2S_MAX_I2S]; /* Right channel buffers */
+} PRUI2S_IoBufC;
+/* PRU I2S FW image info */
+typedef struct PRUI2S_PruFwImageInfo_s {
+ const uint32_t *pPruImemImg;
+ const uint8_t *pPruDmemImg;
+ const uint32_t pruImemImgSz;
+ const uint32_t pruDmemImgSz;
+} PRUI2S_PruFwImageInfo;
+/**
+ * \brief PRU I2S Parameters Structure
+ *
+ * Parameters passed to PRUI2S_init() to configure runtime behavior.
+ * Use PRUI2S_paramsInit() to initialize with default values, then
+ * modify fields as needed before calling PRUI2S_init().
+ *
+ * Example:
+ * PRUI2S_Params params;
+ * PRUI2S_paramsInit(¶ms);
+ * params.pruicss_handle = gPruIcssHandle;
+ * params.txPingPongBaseAddr = (uint32_t)txBuffer;
+ * params.i2sTxCallbackFxn = &myTxCallback;
+ * hPruI2s = PRUI2S_init(CONFIG_PRU_I2S0, ¶ms);
+ */
+typedef struct PRUI2S_Params_s {
+ /* PRUICSS handle - must be set before calling PRUI2S_init() */
+ PRUICSS_Handle pruicss_handle;
+
+ /* Buffer configuration */
+ uint32_t rxPingPongBaseAddr; /* Rx ping/pong base address */
+ uint32_t txPingPongBaseAddr; /* Tx ping/pong base address */
+ uint16_t pingPongBufSz; /* Tx/Rx ping/pong buffer size (bytes) */
+
+ /* Interrupt priorities (VIM: 0=highest, 15=lowest) */
+ uint8_t i2sTxIntrPri; /* I2S Tx interrupt priority */
+ uint8_t i2sRxIntrPri; /* I2S Rx interrupt priority */
+ uint8_t i2sErrIntrPri; /* I2S error interrupt priority */
+
+ /* Callback functions */
+ PRUI2S_CallbackFxn i2sTxCallbackFxn; /* Callback for I2S Tx complete */
+ PRUI2S_CallbackFxn i2sRxCallbackFxn; /* Callback for I2S Rx complete */
+ PRUI2S_CallbackFxn i2sErrCallbackFxn; /* Callback for I2S errors */
+} PRUI2S_Params;
+/* PRU I2S object */
+typedef struct PRUI2S_Object_s {
+ PRUI2S_Params prms; /* Configured parameters */
+
+ void *i2sTxHwiHandle; /* Interrupt handle for I2S Tx */
+ HwiP_Object i2sTxHwiObj; /* Interrupt object for I2S Tx */
+ void *i2sRxHwiHandle; /* Interrupt handle for I2S Rx */
+ HwiP_Object i2sRxHwiObj; /* Interrupt object for I2S Rx */
+ void *i2sErrHwiHandle; /* Interrupt handle I2S error */
+ HwiP_Object i2sErrHwiObj; /* Interrupt object for I2S error */
+
+ Bool isOpen; /* Flag to indicate whether the instance is opened already */
+
+ /* PRU access (r/w) lock */
+ SemaphoreP_Object pruInstlockObj;
+ void *pruInstLock;
+
+ PRUICSS_Handle pruIcssHandle; /* PRU ICSS instance handle */
+
+ /* PRUI2S FW image info */
+ PRUI2S_PruFwImageInfo *pPruFwImageInfo;
+
+ void *rxPingPongBuf; /* Rx ping/pong buffer address */
+ void *txPingPongBuf; /* Tx ping/pong buffer address */
+} PRUI2S_Object;
+
+/**
+ * \brief PRU I2S SW IP Attributes (Legacy - Deprecated)
+ *
+ * DEPRECATED: This structure is being replaced by PRUI2S_Attrs.
+ * Kept for backward compatibility during transition.
+ * New code should use PRUI2S_Attrs and SysConfig-generated configuration.
+ *
+ * This structure mixes runtime-detected and manually-configured values,
+ * which is not the recommended pattern. Use PRUI2S_Attrs instead.
+ */
+typedef struct PRUI2S_SwipAttrs_s {
+ uint32_t baseAddr; /* Base address (calculated from ICSS instance) */
+ uint8_t icssInstId; /* ICSS instance ID (0=ICSSM0, 1=ICSSM1) - from manual config */
+ uint8_t pruInstId; /* PRU core ID (0=PRU0, 1=PRU1) - from manual config */
+ uint8_t numTxI2s; /* Number of Tx I2S (detected from firmware at runtime) */
+ uint8_t numRxI2s; /* Number of Rx I2S (detected from firmware at runtime) */
+ uint8_t sampFreq; /* Sampling frequency in kHz (detected from firmware at runtime) */
+ uint8_t bitsPerSlot; /* Number of bits per I2S slot (detected from firmware at runtime) */
+
+ /* Host interrupt numbers (detected from firmware at runtime) */
+ uint32_t i2sTxHostIntNum; /* I2S Tx host interrupt number */
+ uint32_t i2sRxHostIntNum; /* I2S Rx host interrupt number */
+ uint32_t i2sErrHostIntNum; /* I2S error host interrupt number */
+
+ /* INTC system event numbers (detected from firmware at runtime) */
+ uint8_t i2sTxIcssIntcSysEvt; /* I2S Tx INTC system event */
+ uint8_t i2sRxIcssIntcSysEvt; /* I2S Rx INTC system event */
+ uint8_t i2sErrIcssIntcSysEvt; /* I2S error INTC system event */
+
+ /* Application calls PRUICSS_intcInit() directly before PRUI2S_init() */
+} PRUI2S_SwipAttrs;
+
+
+/* PRU I2S configuration struture */
+typedef struct PRUI2S_Config_s {
+ /* Pointer to PRU I2S object */
+ PRUI2S_Object *object;
+ /* Pointer to PRU I2S SW IP attributes */
+ PRUI2S_SwipAttrs *attrs;
+} PRUI2S_Config;
+
+
+
+/* Driver global state and storage definitions are in pru_i2s_drv.c */
+
+
+/* INTC initialization is application responsibility via PRUICSS_intcInit() */
+
+//#define _DBG_TX_PP_CAP
+#ifdef _DBG_TX_PP_CAP
+/* debug */
+#define PRUI2S_PP_CAP_BUF_SZ ( 360U ) /* Debug capture buffer entries */
+#define TX_PP_CAP_BUF_SZ ( PRUI2S_PP_CAP_BUF_SZ )
+__attribute__((section(".TxPpBufCap"))) uint16_t gTxPpCapBufIdx=0;
+__attribute__((section(".TxPpBufCap"))) uint8_t gTxPpSelCapBuf[TX_PP_CAP_BUF_SZ];
+__attribute__((section(".TxPpBufCap"))) uint32_t gTxPpSrcAddrCapBuf[TX_PP_CAP_BUF_SZ];
+__attribute__((section(".TxPpBufCap"))) uint32_t gTxPpDstAddrCapBuf[TX_PP_CAP_BUF_SZ];
+#endif
+
+//#define _DBG_RX_PP_CAP
+#ifdef _DBG_RX_PP_CAP
+/* debug */
+#define RX_PP_CAP_BUF_SZ ( PRUI2S_PP_CAP_BUF_SZ )
+__attribute__((section(".RxPpBufCap"))) uint16_t gRxPpCapBufIdx=0;
+__attribute__((section(".RxPpBufCap"))) uint8_t gRxPpSelCapBuf[RX_PP_CAP_BUF_SZ];
+__attribute__((section(".RxPpBufCap"))) uint32_t gRxPpSrcAddrCapBuf[RX_PP_CAP_BUF_SZ];
+__attribute__((section(".RxPpBufCap"))) uint32_t gRxPpDstAddrCapBuf[RX_PP_CAP_BUF_SZ];
+#endif
+
+/* ========================================================================== */
+/* Legacy APIs (DEPRECATED) */
+/* ========================================================================== */
+
+/**
+ * \brief Initialize PRU I2S driver
+ *
+ * This function reads configuration from firmware at runtime and initializes
+ * the driver with detected parameters.
+ *
+ * IMPORTANT: Application must call PRUICSS_intcInit() BEFORE calling this function.
+ *
+ * \param pNumValidCfg Output: Number of valid configurations
+ * \param gPruFwImageInfo Pointer to PRU firmware image information
+ *
+ * \return Status code (PRUI2S_DRV_SOK on success)
+ */
+int32_t PRUI2S_init(
+ uint8_t *pNumValidCfg, PRUI2S_PruFwImageInfo (*gPruFwImageInfo)[2]
+);
+
+/**
+ * \brief De-initialize PRU I2S driver
+ *
+ * \return None
+ */
+void PRUI2S_deinit(void);
+
+/**
+ * \brief Set user configuration for PRU I2S instance
+ *
+ * This function must be called before PRUI2S_init() to configure the ICSS instance
+ * and PRU core for each configuration. It calculates the appropriate base address
+ * based on the ICSS instance and PRU core selection.
+ *
+ * \param configIdx Configuration index (0 for first PRU, 1 for second PRU)
+ * \param icssInstId ICSS instance ID (0=ICSSM0, 1=ICSSM1)
+ * \param pruInstId PRU core ID (PRUICSS_PRU0 or PRUICSS_PRU1)
+ *
+ * \return 0 on success, negative error code on failure
+ */
+int32_t PRUI2S_setUserConfig(
+ uint8_t configIdx,
+ uint8_t icssInstId,
+ uint8_t pruInstId
+);
+
+/**
+ * \brief Apply PRU I2S application configuration
+ *
+ * This function applies the user configuration to the PRU I2S driver.
+ * It must be called before PRUI2S_init().
+ *
+ * \return 0 on success, negative error code on failure
+ */
+int32_t PRUI2S_applyAppConfig(void);
+
+/*
+ * Get PRUI2S SW IP attributes for use in application, e.g.
+ * - # Tx I2S
+ * - # Rx I2S
+ * - Sampling frequency
+ * - Slot width (#bits)
+ * - Tx/Rx buffer (ping+pong) size.
+ *
+ * Parameters:
+ * index Index of config to use in the Config array
+ * pCfg Pointer to SW IP in selected config
+ *
+ * return: status code
+ */
+int32_t PRUI2S_getInitCfg(
+ uint32_t index,
+ PRUI2S_SwipAttrs *pCfg
+);
+
+/*
+ * Sets PRU I2S default parameters.
+ *
+ * Parameters:
+ * pPrms Pointer to PRUI2S_Params structure to initialize
+ *
+ * return: none
+ */
+void PRUI2S_paramsInit(
+ PRUI2S_Params *pPrms
+);
+
+/*
+ * Opens PRU I2S instance:
+ * - Clears associated ICSS IMEM/DMEM
+ * - Initializes ICSS INTC
+ * - Downloads firmware to PRU (IMEM/DMEM)
+ * - Constructs interrupts & registers interrupt callbacks.
+ *
+ * Parameters:
+ * index Index of config to use in the Config array
+ * pPrms Pointer to open parameters. If NULL is passed, then
+ * default values will be used
+ *
+ * return: status code
+ */
+PRUI2S_Handle PRUI2S_open(
+ uint32_t index,
+ PRUI2S_Params *pPrms
+);
+
+/* Closes PRU I2S instance:
+ * - Disables PRU
+ * - Resets PRU
+ * - Clears associated ICSS IMEM/DMEM.
+ * - Destructs interrupts.
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ *
+ * return: status code
+*/
+int32_t PRUI2S_close(
+ PRUI2S_Handle handle
+);
+
+/*
+ * Enables PRU I2S instance
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ *
+ * return: status code
+ */
+int32_t PRUI2S_enable(
+ PRUI2S_Handle handle
+);
+
+/*
+ * Initializes IO Buffer with default parameters.
+ * Same IO Buffer stucture used for write and read.
+ *
+ * Parameters:
+ * pIoBuf Pointer to PRUI2S_IoBuf structure to initialize
+ *
+ * return: none
+ */
+void PRUI2S_ioBufInit(
+ PRUI2S_IoBuf *pIoBuf
+);
+
+/*
+ * Writes I2S Tx data buffer to current PRU FW I2S Tx buffer (ping or pong).
+ * I2S Tx data buffer in interleaved format, i.e. no format change.
+ * - PRU FW I2S Tx buffer is located in ICSS memory.
+ * - PRU FW I2S Tx buffer address & length are contained in FW build
+ * (and SW IP attributes after call to PRUI2S_Init()).
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * pIoBuf Pointer to PRUI2S_IoBuf structure to use for write
+ *
+ * return: status code
+ */
+int32_t PRUI2S_write(
+ PRUI2S_Handle handle,
+ PRUI2S_IoBuf *pIoBuf
+);
+
+/*
+ * Reads I2S Rx data buffer from current PRU FW I2S Rx buffer (ping or pong).
+ * I2S Rx data buffer in interleaved format, i.e. no format change.
+ * - PRU FW I2S Rx buffer location is determined by application.
+ * - PRU FW I2S Rx buffer length is contained in FW build
+ * (and SW IP attributes after call to PRUI2S_Init()).
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * pIoBuf Pointer to PRUI2S_IoBuf structure to use for read
+ *
+ * return: status code
+ */
+int32_t PRUI2S_read(
+ PRUI2S_Handle handle,
+ PRUI2S_IoBuf *pIoBuf
+);
+
+/*
+ * Initializes conversion IO Buffer with default parameters.
+ *
+ * Parameters:
+ * pIoBuf Pointer to PRUI2S_IoBufC structure to initialize
+ *
+ * return: none
+ */
+void PRUI2S_ioBufCInit(
+ PRUI2S_IoBufC *pIoBufC
+);
+
+/*
+ * Writes I2S Tx data buffers to current PRU FW I2S Tx buffer (ping or pong).
+ * I2S Tx data buffers in non-interleaved format, buffers are written to
+ * current I2S Tx buffer (ping or ping) in interleaved format.
+ * - PRU FW I2S Tx buffer is located in ICSS memory.
+ * - PRU FW I2S Tx buffer address & length are contained in FW build
+ * (and SW IP attributes after call to PRUI2S_Init()).
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * pIoBufC Pointer to PRUI2S_IoBufC structure to use for write
+ *
+ * return: status code
+ */
+int32_t PRUI2S_writeC(
+ PRUI2S_Handle handle,
+ PRUI2S_IoBufC *pIoBufC
+);
+
+/*
+ * Reads I2S Rx data buffer from current PRU FW I2S Rx buffer (ping or pong).
+ * I2S Rx data buffers in non-interleaved format, buffers are read from
+ * current I2S Rx buffer (ping or ping) in interleaved format.
+ * - PRU FW I2S Rx buffer location is determined by application.
+ * - PRU FW I2S Rx buffer length is contained in FW build
+ * (and SW IP attributes after call to PRUI2S_Init()).
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * pIoBufC Pointer to PRUI2S_IoBufC structure to use for read
+ *
+ * return: status code
+ */
+int32_t PRUI2S_readC(
+ PRUI2S_Handle handle,
+ PRUI2S_IoBufC *pIoBufC
+);
+
+/*
+ * Gets error status.
+ * Application calls this function to obtain error status and
+ * determine cause of errors.
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * pErrStat Pointer to errot status bit-field.
+ *
+ * return: none
+ */
+void PRUI2S_getErrStat(
+ PRUI2S_Handle handle,
+ uint8_t *pErrStat
+);
+
+/*
+ * Clears error status.
+ * Application calls this function to clear error status.
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * pErrStat Pointer to errot status bit-field mask.
+ *
+ * return: none
+ */
+void PRUI2S_clearErrStat(
+ PRUI2S_Handle handle,
+ uint8_t errMask
+);
+
+/*
+ * Disables PRUI2S interrupt
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * intrType Type of interrupt to disable, I2S Tx/Rx or I2S error
+ *
+ * return: status code
+ */
+int32_t PRUI2S_disableInt(
+ PRUI2S_Handle handle,
+ uint8_t intrType
+);
+
+/*
+ * Enables PRUI2S interrupt
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * intrType Type of interrupt to disable, I2S Tx/Rx or I2S error
+ *
+ * return: status code
+ */
+int32_t PRUI2S_enableInt(
+ PRUI2S_Handle handle,
+ uint8_t intrType
+);
+
+/*
+ * Clears PRUI2S interrupt
+ *
+ * Parameters:
+ * handle PRUI2S_Handle returned from PRUI2S_open()
+ * intrType Type of interrupt to disable, I2S Tx/Rx or I2S error
+ *
+ * return: status code
+ */
+int32_t PRUI2S_clearInt(
+ PRUI2S_Handle handle,
+ uint8_t intrType
+);
+
+/**
+ * \brief This function enables an INTC event. It should be called only after
+ * successful execution of #PRUICSS_intcInit().
+ *
+ * \param handle #PRUICSS_Handle returned from #PRUICSS_open()
+ * \param eventnum The INTC Event number
+ *
+ * \return #SystemP_SUCCESS in case of successful transition, #SystemP_FAILURE
+ * otherwise
+ */
+int32_t PRUICSS_enableEvent(
+ PRUICSS_Handle handle,
+ uint32_t eventnum
+);
+
+/**
+ * \brief This function disables an INTC event. It should be called only after
+ * successful execution of #PRUICSS_intcInit().
+ *
+ * \param handle #PRUICSS_Handle returned from #PRUICSS_open()
+ * \param eventnum The INTC Event number
+ *
+ * \return #SystemP_SUCCESS in case of successful transition, #SystemP_FAILURE
+ * otherwise
+ */
+int32_t PRUICSS_disableEvent(
+ PRUICSS_Handle handle,
+ uint32_t eventnum
+);
+
+/* Application calls PRUICSS_intcInit() directly for initialization.
+ * Runtime control uses PRUICSS_enableEvent() and PRUICSS_disableEvent().
+ */
+
+/**
+ * \brief Extracts information in PRU FW pseudo-registers, update SW IP using extracted info.
+ * Info is contained in PRU FW DMEM image.
+ *
+ * \param pPruFwImageInfo Pointer to PRU FW image info structure
+ * \param pSwipAttrs Pointer to SW IP attributes structure
+ *
+ * \return int32_t Status of the operation
+ */
+static int32_t PRUI2S_getPruFwImageInfo(
+ PRUI2S_PruFwImageInfo *pPruFwImageInfo,
+ PRUI2S_SwipAttrs *pSwipAttrs
+);
+
+/**
+ * \brief Checks SW IP parameters
+ *
+ * \param pSwipAttrs Pointer to SW IP attributes structure
+ *
+ * \return int32_t Status of the operation
+ */
+static int32_t PRUI2S_checkSwipParams(
+ PRUI2S_SwipAttrs *pSwipAttrs
+);
+
+/**
+ * \brief Checks parameters used for PRUI2S_open() function
+ *
+ * \param pSwipAttrs Pointer to SW IP attributes structure
+ * \param pPrms Pointer to PRU I2S parameters structure
+ *
+ * \return int32_t Status of the operation
+ */
+static int32_t PRUI2S_checkOpenParams(
+ PRUI2S_SwipAttrs *pSwipAttrs,
+ PRUI2S_Params *pPrms
+);
+
+/**
+ * \brief Initializes PRU for PRU I2S
+ *
+ * \param pCfg Pointer to PRU I2S configuration structure
+ *
+ * \return int32_t Status of the operation
+ */
+static int32_t PRUI2S_initPru(
+ PRUI2S_Config *pCfg
+);
+
+/* INTC initialization is application responsibility via PRUICSS_intcInit() */
+
+/**
+ * \brief Initializes PRU I2S FW
+ *
+ * \param pCfg Pointer to PRU I2S configuration structure
+ *
+ * \return int32_t Status of the operation
+ */
+static int32_t PRUI2S_initFw(
+ PRUI2S_Config *pCfg
+);
+
+/**
+ * \brief Initializes PRU I2S ping/pong buffers
+ *
+ * \param pCfg Pointer to PRU I2S configuration structure
+ *
+ * \return int32_t Status of the operation
+ */
+static int32_t PRUI2S_initPpBufs(
+ PRUI2S_Config *pCfg
+);
+
+/**
+ * \brief De-initializes PRU for PRU I2S
+ *
+ * \param pCfg Pointer to PRU I2S configuration structure
+ *
+ * \return int32_t Status of the operation
+ */
+static int32_t PRUI2S_deinitPru(
+ PRUI2S_Config *pCfg
+);
+
+#endif /* PRU_I2S_DRV_H_ */
diff --git a/examples/pru_i2s/makefile b/examples/pru_i2s/makefile
new file mode 100644
index 000000000..3db2968b2
--- /dev/null
+++ b/examples/pru_i2s/makefile
@@ -0,0 +1,186 @@
+include ../../imports.mak
+
+#######################
+# Library build tools #
+#######################
+ifeq ($(CG_TOOL_ROOT),)
+ CC=$(CGT_TI_ARM_CLANG_PATH)/bin/tiarmclang
+ AR=$(CGT_TI_ARM_CLANG_PATH)/bin/tiarmar
+else
+ CC=$(CG_TOOL_ROOT)/bin/tiarmclang
+ AR=$(CG_TOOL_ROOT)/bin/tiarmar
+endif
+
+CFLAGS_AM261X := -mcpu=cortex-r5 -mfloat-abi=hard -mfpu=vfpv3-d16 -mthumb -Wall -Werror -g -Wno-gnu-variable-sized-type-not-at-end -Wno-unused-function -Os
+CFLAGS_AM263X := -mcpu=cortex-r5 -mfloat-abi=hard -mfpu=vfpv3-d16 -mthumb -Wall -Werror -g -Wno-gnu-variable-sized-type-not-at-end -Wno-unused-function -Os
+
+INCLUDES_AM261X := \
+ -I$(MCU_PLUS_SDK_PATH)/source \
+ -I$(OPEN_PRU_PATH)/source \
+ -I$(MCU_PLUS_SDK_PATH)/source/kernel/freertos/FreeRTOS-Kernel/include \
+ -I$(MCU_PLUS_SDK_PATH)/source/kernel/freertos/portable/TI_ARM_CLANG/ARM_CR5F \
+ -I$(MCU_PLUS_SDK_PATH)/source/kernel/freertos/config/am261x/r5f \
+ -I./include \
+ -I./firmware \
+ -I. \
+ -I.. \
+ -I$(OPEN_PRU_PATH)/examples
+
+INCLUDES_AM263X := \
+ -I$(MCU_PLUS_SDK_PATH)/source \
+ -I$(OPEN_PRU_PATH)/source \
+ -I$(MCU_PLUS_SDK_PATH)/source/kernel/freertos/FreeRTOS-Kernel/include \
+ -I$(MCU_PLUS_SDK_PATH)/source/kernel/freertos/portable/TI_ARM_CLANG/ARM_CR5F \
+ -I$(MCU_PLUS_SDK_PATH)/source/kernel/freertos/config/am263x/r5f \
+ -I./include \
+ -I./firmware \
+ -I. \
+ -I.. \
+ -I$(OPEN_PRU_PATH)/examples
+
+DEFINES_AM261X := -DSOC_AM261X -DOS_FREERTOS
+DEFINES_AM263X := -DSOC_AM263X -DOS_FREERTOS
+
+#######################
+# project information #
+#######################
+
+PROJECT_NAME := pru_i2s
+SUPPORTED_PROCESSORS := am261x am263x
+# Does the PRU code have dependencies outside of the open-pru repo?
+PRU_DEPENDENCIES := mcuplus
+# Use NON_PRU_DEPENDENCIES to select which makefiles to call for non-PRU cores
+NON_PRU_DEPENDENCIES := mcuplus
+
+###################
+# Prebuild checks #
+###################
+BUILD_PROJECT := y
+DEVICE_NON_PRU :=
+
+# Only build project if $(DEVICE) is in $(SUPPORTED_PROCESSORS)
+ifeq (,$(findstring $(DEVICE),$(SUPPORTED_PROCESSORS)))
+BUILD_PROJECT := n
+MESSAGE := Project $(PROJECT_NAME) does not have a build option for $(DEVICE)
+endif
+
+# Only build project if PRU dependencies exist
+ifneq (,$(PRU_DEPENDENCIES))
+# MCU+ SDK dependency?
+ifeq (mcuplus,$(findstring mcuplus,$(PRU_DEPENDENCIES)))
+ifneq ($(BUILD_MCUPLUS),y)
+BUILD_PROJECT := n
+MESSAGE ?= Project $(PROJECT_NAME) depends on MCU+ SDK, but BUILD_MCUPLUS != y.
+endif
+endif
+# Additional PRU dependency checks go here. For example:
+#ifeq (dependency,$(findstring dependency,$(PRU_DEPENDENCIES)))
+#if (dependency check fails)
+#BUILD_PROJECT := n
+#MESSAGE ?= Project $(PROJECT_NAME) depends on dependency, but dependency does not exist.
+#endif
+#endif
+endif
+
+# Only build non-PRU code if the non-PRU code is enabled in imports.mak
+ifeq ($(BUILD_MCUPLUS),y)
+ifeq (mcuplus,$(findstring mcuplus,$(NON_PRU_DEPENDENCIES)))
+DEVICE_NON_PRU += $(DEVICE)_mcuplus
+endif
+endif
+ifeq ($(BUILD_LINUX),y)
+ifeq (linux,$(findstring linux,$(NON_PRU_DEPENDENCIES)))
+DEVICE_NON_PRU += $(DEVICE)_linux
+endif
+endif
+
+###########################
+# Make and clean commands #
+###########################
+
+# "make pru" builds PRU firmware for all supported devices
+pru: ARGUMENTS_PRU = all
+pru: ARGUMENTS_MCUPLUS = all
+pru: MESSAGE = "Building $(PROJECT_NAME) PRU firmware"
+pru: pre_build_message $(SUPPORTED_PROCESSORS)
+
+# "make host" builds host (R5F/ARM) code for specified DEVICE
+host: ARGUMENTS_PRU = pru
+host: ARGUMENTS_MCUPLUS = all
+host: MESSAGE = "Building $(PROJECT_NAME) host code for $(DEVICE)"
+host: pre_build_message $(DEVICE_NON_PRU)
+
+ifeq ($(BUILD_PROJECT),y)
+# "make" or "make all" builds projects that match $(DEVICE) set in imports.mak
+all: ARGUMENTS_PRU = all
+all: ARGUMENTS_MCUPLUS = $(ARGUMENTS_PRU)
+all: MESSAGE = "Building $(PROJECT_NAME) for $(DEVICE)"
+all: pre_build_message $(DEVICE) $(DEVICE_NON_PRU)
+
+# "make clean" cleans projects that match $(DEVICE) set in imports.mak
+clean: ARGUMENTS_PRU = clean
+clean: ARGUMENTS_MCUPLUS = scrub
+clean: MESSAGE = "Cleaning $(PROJECT_NAME) for $(DEVICE)"
+clean: pre_build_message $(DEVICE) $(DEVICE_NON_PRU)
+
+else
+# if a prebuild check failed, print message and exit
+all clean: pre_build_message
+endif
+
+pre_build_message:
+ @echo $(MESSAGE)
+
+######################
+# Target definitions #
+######################
+
+# provide target definitions for each supported processor
+# PRU firmware should be built before any RTOS code that includes it
+am261x:
+# am261x-lp - I2S protocol
+ $(MAKE) -C firmware/I2S/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt $(ARGUMENTS_PRU)
+ $(MAKE) -C firmware/I2S/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt $(ARGUMENTS_PRU)
+# am261x-lp - TDM4 protocol
+ $(MAKE) -C firmware/TDM4/pru0_tx/am261x-lp/icssm0-pru0_fw/ti-pru-cgt $(ARGUMENTS_PRU)
+ $(MAKE) -C firmware/TDM4/pru1_rx/am261x-lp/icssm0-pru1_fw/ti-pru-cgt $(ARGUMENTS_PRU)
+
+am261x_mcuplus: build_lib_am261x
+# am261x-lp - R5F application
+ $(MAKE) -C pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang $(ARGUMENTS_MCUPLUS)
+
+build_lib_am261x:
+# am261x-lp - Build driver library (always rebuild by removing old lib and objects first)
+ $(RM) lib/pru_i2s.am261x.r5f.ti-arm-clang.*.lib lib/pru_i2s_*_am261x.obj
+ $(MKDIR) lib
+ @echo "Building pru_i2s library for am261x..."
+ $(CC) -c $(CFLAGS_AM261X) $(INCLUDES_AM261X) $(DEFINES_AM261X) -o lib/pru_i2s_drv_am261x.obj driver/pru_i2s_drv.c
+ $(CC) -c $(CFLAGS_AM261X) $(INCLUDES_AM261X) $(DEFINES_AM261X) -o lib/pru_i2s_app_config_am261x.obj pru_i2s_app/pru_i2s_app_config.c
+ $(AR) rc lib/pru_i2s.am261x.r5f.ti-arm-clang.release.lib lib/pru_i2s_drv_am261x.obj lib/pru_i2s_app_config_am261x.obj
+ $(RM) lib/pru_i2s_*_am261x.obj
+ @echo "Library build complete."
+
+am263x:
+# am263x-cc - I2S protocol
+ $(MAKE) -C firmware/I2S/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt $(ARGUMENTS_PRU)
+ $(MAKE) -C firmware/I2S/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt $(ARGUMENTS_PRU)
+# am263x-cc - TDM4 protocol
+ $(MAKE) -C firmware/TDM4/pru0_tx/am263x-cc/icssm0-pru0_fw/ti-pru-cgt $(ARGUMENTS_PRU)
+ $(MAKE) -C firmware/TDM4/pru1_rx/am263x-cc/icssm0-pru1_fw/ti-pru-cgt $(ARGUMENTS_PRU)
+
+am263x_mcuplus: build_lib_am263x
+# am263x-cc - R5F application
+ $(MAKE) -C pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang $(ARGUMENTS_MCUPLUS)
+
+build_lib_am263x:
+# am263x-cc - Build driver library (always rebuild by removing old lib and objects first)
+ $(RM) lib/pru_i2s.am263x.r5f.ti-arm-clang.*.lib lib/pru_i2s_*_am263x.obj
+ $(MKDIR) lib
+ @echo "Building pru_i2s library for am263x..."
+ $(CC) -c $(CFLAGS_AM263X) $(INCLUDES_AM263X) $(DEFINES_AM263X) -o lib/pru_i2s_drv_am263x.obj driver/pru_i2s_drv.c
+ $(CC) -c $(CFLAGS_AM263X) $(INCLUDES_AM263X) $(DEFINES_AM263X) -o lib/pru_i2s_app_config_am263x.obj pru_i2s_app/pru_i2s_app_config.c
+ $(AR) rc lib/pru_i2s.am263x.r5f.ti-arm-clang.release.lib lib/pru_i2s_drv_am263x.obj lib/pru_i2s_app_config_am263x.obj
+ $(RM) lib/pru_i2s_*_am263x.obj
+ @echo "Library build complete."
+
+.PHONY: all clean pru host pre_build_message $(DEVICE) $(DEVICE_NON_PRU) $(SUPPORTED_PROCESSORS)
diff --git a/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/example.syscfg b/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/example.syscfg
new file mode 100644
index 000000000..158d3bad7
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/example.syscfg
@@ -0,0 +1,359 @@
+/**
+ * These arguments were used when this file was generated. They will be automatically applied on subsequent loads
+ * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments.
+ * @cliArgs --device "AM261x_ZFG" --part "AM2612" --package "ZFG" --context "r5fss0-0" --product "OPEN_PRU@07.03.01" --product "MCU_PLUS_SDK_AM261x@11.00.00"
+ * @v2CliArgs --device "AM2612" --package "NFBGA (ZFG)" --variant "500MHz" --context "r5fss0-0" --product "OPEN_PRU@07.03.01" --product "MCU_PLUS_SDK_AM261x@11.00.00"
+ * @versions {"tool":"1.25.0+4268"}
+ */
+
+/**
+ * Import the modules used in this configuration.
+ */
+const ioexp = scripting.addModule("/board/ioexp/ioexp", {}, false);
+const ioexp1 = ioexp.addInstance();
+const gpio = scripting.addModule("/drivers/gpio/gpio", {}, false);
+const gpio1 = gpio.addInstance();
+const pruicss = scripting.addModule("/drivers/pruicss/pruicss", {}, false);
+const pruicss1 = pruicss.addInstance();
+const debug_log = scripting.addModule("/kernel/dpl/debug_log");
+const mpu_armv7 = scripting.addModule("/kernel/dpl/mpu_armv7", {}, false);
+const mpu_armv71 = mpu_armv7.addInstance();
+const mpu_armv72 = mpu_armv7.addInstance();
+const mpu_armv73 = mpu_armv7.addInstance();
+const mpu_armv74 = mpu_armv7.addInstance();
+const mpu_armv75 = mpu_armv7.addInstance();
+const mpu_armv76 = mpu_armv7.addInstance();
+const mpu_armv77 = mpu_armv7.addInstance();
+const mpu_armv78 = mpu_armv7.addInstance();
+const default_linker = scripting.addModule("/memory_configurator/default_linker", {}, false);
+const default_linker1 = default_linker.addInstance();
+const general = scripting.addModule("/memory_configurator/general", {}, false);
+const general1 = general.addInstance();
+const region = scripting.addModule("/memory_configurator/region", {}, false);
+const region1 = region.addInstance();
+const section = scripting.addModule("/memory_configurator/section", {}, false);
+const section1 = section.addInstance();
+const section2 = section.addInstance();
+const section3 = section.addInstance();
+const section4 = section.addInstance();
+const section5 = section.addInstance();
+const section6 = section.addInstance();
+const section7 = section.addInstance();
+const section8 = section.addInstance();
+const section9 = section.addInstance();
+const section10 = section.addInstance();
+const section11 = section.addInstance();
+const section12 = section.addInstance();
+const section13 = section.addInstance();
+
+/**
+ * Write custom configuration values to the imported modules.
+ */
+ioexp1.$name = "CONFIG_IOEXP0";
+ioexp1.TCA6408ARGTR_port0_pinBP_MUX_SW_S1_mode = 0;
+ioexp1.TCA6408ARGTR_port0_pinBP_MUX_SW_SO_mode = 0;
+ioexp1.TCA6408ARGTR_port0_pinBP_MUX_SW_SO_state = 1;
+ioexp1.TCA6408ARGTR_port0_pinBP_BO_MUX_EN_state = 1;
+ioexp1.TCA6408ARGTR_port0_pinBP_BO_MUX_EN_N_mode = 0;
+
+gpio1.$name = "CONFIG_GPIO0";
+
+const i2c = scripting.addModule("/drivers/i2c/i2c", {}, false);
+const i2c1 = i2c.addInstance({}, false);
+i2c1.$name = "CONFIG_I2C0";
+ioexp1.peripheralDriver = i2c1;
+i2c1.I2C.$assign = "I2C0";
+i2c1.I2C_child.$name = "drivers_i2c_v1_i2c_v1_template1";
+
+pruicss1.$name = "CONFIG_PRU_ICSS0";
+pruicss1.instance = "ICSSM1";
+pruicss1.AdditionalICSSSettings[0].$name = "CONFIG_PRU_ICSS_IO0";
+pruicss1.AdditionalICSSSettings[0].PruGPIO.create(1);
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].$name = "CONFIG_PRU_ICSS_GPIO0";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO5.rx = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO5.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO9.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO12.rx = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO12.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO9.rx = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO9.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO7.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO13.rx = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO13.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO5.rx = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO5.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO8.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO6.rx = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO6.$used = true;
+
+mpu_armv71.$name = "CONFIG_MPU_REGION0";
+mpu_armv71.size = 31;
+mpu_armv71.attributes = "Device";
+mpu_armv71.accessPermissions = "Supervisor RD+WR, User RD";
+mpu_armv71.allowExecute = false;
+
+mpu_armv72.$name = "CONFIG_MPU_REGION1";
+mpu_armv72.size = 15;
+mpu_armv72.accessPermissions = "Supervisor RD+WR, User RD";
+
+mpu_armv73.$name = "CONFIG_MPU_REGION2";
+mpu_armv73.baseAddr = 0x80000;
+mpu_armv73.size = 15;
+mpu_armv73.accessPermissions = "Supervisor RD+WR, User RD";
+
+mpu_armv74.$name = "CONFIG_MPU_REGION3";
+mpu_armv74.accessPermissions = "Supervisor RD+WR, User RD";
+mpu_armv74.baseAddr = 0x70000000;
+mpu_armv74.size = 21;
+
+mpu_armv75.$name = "CONFIG_MPU_REGION4";
+mpu_armv75.size = 14;
+mpu_armv75.baseAddr = 0x50D00000;
+mpu_armv75.allowExecute = false;
+mpu_armv75.attributes = "Device";
+
+mpu_armv76.$name = "CONFIG_MPU_REGION5";
+mpu_armv76.size = 14;
+mpu_armv76.allowExecute = false;
+mpu_armv76.attributes = "Device";
+mpu_armv76.baseAddr = 0x72000000;
+
+mpu_armv77.$name = "CONFIG_MPU_REGION6";
+mpu_armv77.baseAddr = 0x700C0000;
+mpu_armv77.size = 18;
+mpu_armv77.attributes = "Cached+Sharable";
+mpu_armv77.allowExecute = false;
+
+mpu_armv78.$name = "CONFIG_MPU_REGION7";
+mpu_armv78.baseAddr = 0x48010000;
+mpu_armv78.size = 15;
+mpu_armv78.attributes = "Cached+Sharable";
+mpu_armv78.allowExecute = false;
+
+default_linker1.$name = "memory_configurator_default_linker0";
+
+general1.$name = "CONFIG_GENERAL0";
+general1.linker.$name = "TIARMCLANG0";
+
+region1.$name = "MEMORY_REGION_CONFIGURATION0";
+region1.memory_region.create(11);
+region1.memory_region[0].type = "TCMA";
+region1.memory_region[0].$name = "R5F_VECS";
+region1.memory_region[0].size = 0x40;
+region1.memory_region[0].auto = false;
+region1.memory_region[1].type = "TCMA";
+region1.memory_region[1].$name = "R5F_TCMA";
+region1.memory_region[1].size = 0x7FC0;
+region1.memory_region[2].type = "TCMB";
+region1.memory_region[2].size = 0x8000;
+region1.memory_region[2].$name = "R5F_TCMB";
+region1.memory_region[3].$name = "OCRAM";
+region1.memory_region[3].auto = false;
+region1.memory_region[3].size = 0x40000;
+region1.memory_region[3].manualStartAddress = 0x70080000;
+region1.memory_region[4].type = "FLASH";
+region1.memory_region[4].auto = false;
+region1.memory_region[4].size = 0x80000;
+region1.memory_region[4].$name = "FLASH";
+region1.memory_region[5].$name = "USER_SHM_MEM";
+region1.memory_region[5].manualStartAddress = 0x701D0000;
+region1.memory_region[5].size = 0x4000;
+region1.memory_region[5].isShared = true;
+region1.memory_region[5].shared_cores = ["r5fss0-1"];
+region1.memory_region[6].$name = "LOG_SHM_MEM";
+region1.memory_region[6].manualStartAddress = 0x701D4000;
+region1.memory_region[6].size = 0x4000;
+region1.memory_region[6].isShared = true;
+region1.memory_region[6].shared_cores = ["r5fss0-1"];
+region1.memory_region[7].type = "CUSTOM";
+region1.memory_region[7].$name = "RTOS_NORTOS_IPC_SHM_MEM";
+region1.memory_region[7].auto = false;
+region1.memory_region[7].manualStartAddress = 0x72000000;
+region1.memory_region[7].size = 0x3E80;
+region1.memory_region[7].isShared = true;
+region1.memory_region[7].shared_cores = ["r5fss0-1"];
+region1.memory_region[8].auto = false;
+region1.memory_region[8].size = 0x7F00;
+region1.memory_region[8].type = "CUSTOM";
+region1.memory_region[8].$name = "ICSSM_SHMEM";
+region1.memory_region[8].manualStartAddress = 0x48010100;
+region1.memory_region[9].size = 0x40000;
+region1.memory_region[9].auto = false;
+region1.memory_region[9].manualStartAddress = 0x700C0000;
+region1.memory_region[9].$name = "OCRAM_256K3_RAM";
+region1.memory_region[10].auto = false;
+region1.memory_region[10].manualStartAddress = 0x70100000;
+region1.memory_region[10].$name = "OCRAM_256K4_RAM";
+region1.memory_region[10].size = 0x40000;
+
+section1.load_memory = "R5F_VECS";
+section1.group = false;
+section1.$name = "Vector Table";
+section1.output_section.create(1);
+section1.output_section[0].$name = ".vectors";
+section1.output_section[0].palignment = true;
+
+section2.load_memory = "OCRAM";
+section2.$name = "Text Segments";
+section2.output_section.create(5);
+section2.output_section[0].$name = ".text.hwi";
+section2.output_section[0].palignment = true;
+section2.output_section[1].$name = ".text.cache";
+section2.output_section[1].palignment = true;
+section2.output_section[2].$name = ".text.mpu";
+section2.output_section[2].palignment = true;
+section2.output_section[3].$name = ".text.boot";
+section2.output_section[3].palignment = true;
+section2.output_section[4].$name = ".text:abort";
+section2.output_section[4].palignment = true;
+
+section3.load_memory = "OCRAM";
+section3.$name = "Code and Read-Only Data";
+section3.output_section.create(2);
+section3.output_section[0].$name = ".text";
+section3.output_section[0].palignment = true;
+section3.output_section[1].$name = ".rodata";
+section3.output_section[1].palignment = true;
+
+section4.load_memory = "OCRAM";
+section4.$name = "Data Segment";
+section4.output_section.create(1);
+section4.output_section[0].$name = ".data";
+section4.output_section[0].palignment = true;
+
+section5.load_memory = "OCRAM";
+section5.$name = "Memory Segments";
+section5.output_section.create(3);
+section5.output_section[0].$name = ".bss";
+section5.output_section[0].output_sections_start = "__BSS_START";
+section5.output_section[0].output_sections_end = "__BSS_END";
+section5.output_section[0].palignment = true;
+section5.output_section[1].$name = ".sysmem";
+section5.output_section[1].palignment = true;
+section5.output_section[2].$name = ".stack";
+section5.output_section[2].palignment = true;
+
+section6.load_memory = "OCRAM";
+section6.$name = "Stack Segments";
+section6.output_section.create(5);
+section6.output_section[0].$name = ".irqstack";
+section6.output_section[0].output_sections_start = "__IRQ_STACK_START";
+section6.output_section[0].output_sections_end = "__IRQ_STACK_END";
+section6.output_section[0].input_section.create(1);
+section6.output_section[0].input_section[0].$name = ". = . + __IRQ_STACK_SIZE;";
+section6.output_section[1].$name = ".fiqstack";
+section6.output_section[1].output_sections_start = "__FIQ_STACK_START";
+section6.output_section[1].output_sections_end = "__FIQ_STACK_END";
+section6.output_section[1].input_section.create(1);
+section6.output_section[1].input_section[0].$name = ". = . + __FIQ_STACK_SIZE;";
+section6.output_section[2].$name = ".svcstack";
+section6.output_section[2].output_sections_start = "__SVC_STACK_START";
+section6.output_section[2].output_sections_end = "__SVC_STACK_END";
+section6.output_section[2].input_section.create(1);
+section6.output_section[2].input_section[0].$name = ". = . + __SVC_STACK_SIZE;";
+section6.output_section[3].$name = ".abortstack";
+section6.output_section[3].output_sections_start = "__ABORT_STACK_START";
+section6.output_section[3].output_sections_end = "__ABORT_STACK_END";
+section6.output_section[3].input_section.create(1);
+section6.output_section[3].input_section[0].$name = ". = . + __ABORT_STACK_SIZE;";
+section6.output_section[4].$name = ".undefinedstack";
+section6.output_section[4].output_sections_start = "__UNDEFINED_STACK_START";
+section6.output_section[4].output_sections_end = "__UNDEFINED_STACK_END";
+section6.output_section[4].input_section.create(1);
+section6.output_section[4].input_section[0].$name = ". = . + __UNDEFINED_STACK_SIZE;";
+
+section7.load_memory = "OCRAM";
+section7.$name = "Initialization and Exception Handling";
+section7.output_section.create(3);
+section7.output_section[0].$name = ".ARM.exidx";
+section7.output_section[0].palignment = true;
+section7.output_section[1].$name = ".init_array";
+section7.output_section[1].palignment = true;
+section7.output_section[2].$name = ".fini_array";
+section7.output_section[2].palignment = true;
+
+section8.load_memory = "USER_SHM_MEM";
+section8.type = "NOLOAD";
+section8.$name = "User Shared Memory";
+section8.group = false;
+section8.output_section.create(1);
+section8.output_section[0].$name = ".bss.user_shared_mem";
+section8.output_section[0].alignment = 0;
+
+section9.load_memory = "LOG_SHM_MEM";
+section9.$name = "Log Shared Memory";
+section9.group = false;
+section9.type = "NOLOAD";
+section9.output_section.create(1);
+section9.output_section[0].$name = ".bss.log_shared_mem";
+section9.output_section[0].alignment = 0;
+
+section10.load_memory = "RTOS_NORTOS_IPC_SHM_MEM";
+section10.type = "NOLOAD";
+section10.$name = "IPC Shared Memory";
+section10.group = false;
+section10.output_section.create(1);
+section10.output_section[0].$name = ".bss.ipc_vring_mem";
+section10.output_section[0].alignment = 0;
+
+section11.$name = "CONFIG_SECTION0";
+section11.group = false;
+section11.load_memory = "OCRAM_256K3_RAM";
+section11.output_section.create(1);
+section11.output_section[0].$name = ".PruI2s1RxPingPongBuf";
+section11.output_section[0].alignment = 0;
+
+section12.$name = "CONFIG_SECTION1";
+section12.group = false;
+section12.load_memory = "OCRAM_256K4_RAM";
+section12.output_section.create(1);
+section12.output_section[0].$name = ".TxBuf";
+section12.output_section[0].fill = 2863329520;
+section12.output_section[0].alignment = 0;
+
+section13.$name = "CONFIG_SECTION2";
+section13.group = false;
+section13.load_memory = "OCRAM_256K4_RAM";
+section13.output_section.create(1);
+section13.output_section[0].fill = 1431655765;
+section13.output_section[0].$name = ".RxBuf";
+section13.output_section[0].macro_name = "RXBUF_SECTION";
+section13.output_section[0].alignment = 0;
+
+/**
+ * Pinmux solution for unlocked pins/peripherals. This ensures that minor changes to the automatic solver in a future
+ * version of the tool will not impact the pinmux you originally saw. These lines can be completely deleted in order to
+ * re-solve from scratch.
+ */
+gpio1.GPIO_n.$suggestSolution = "GPIO0";
+i2c1.I2C.SCL.$suggestSolution = "GPIO135";
+i2c1.I2C.SDA.$suggestSolution = "GPIO134";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].$suggestSolution = "PRU-ICSS1";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO5.$suggestSolution = "GPIO54";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO9.$suggestSolution = "GPIO12";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO12.$suggestSolution = "GPIO4";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO9.$suggestSolution = "GPIO74";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO7.$suggestSolution = "GPIO122";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU1_GPIO13.$suggestSolution = "GPIO125";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO5.$suggestSolution = "GPIO43";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO8.$suggestSolution = "GPIO44";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0]["PRU-ICSS1"].PR1_PRU0_GPIO6.$suggestSolution = "GPIO45";
+pruicss1.intcMapping.create(6);
+pruicss1.intcMapping[0].$name = "CONFIG_PRU_I2S_PRU0_TX";
+pruicss1.intcMapping[0].event = "18";
+pruicss1.intcMapping[0].channel = "2";
+pruicss1.intcMapping[1].$name = "CONFIG_PRU_I2S_PRU0_RX";
+pruicss1.intcMapping[1].event = "19";
+pruicss1.intcMapping[1].channel = "3";
+pruicss1.intcMapping[2].$name = "CONFIG_PRU_I2S_PRU0_ERR";
+pruicss1.intcMapping[2].event = "20";
+pruicss1.intcMapping[2].channel = "4";
+pruicss1.intcMapping[3].$name = "CONFIG_PRU_I2S_PRU1_TX";
+pruicss1.intcMapping[3].event = "21";
+pruicss1.intcMapping[3].channel = "5";
+pruicss1.intcMapping[4].$name = "CONFIG_PRU_I2S_PRU1_RX";
+pruicss1.intcMapping[4].event = "22";
+pruicss1.intcMapping[4].channel = "6";
+pruicss1.intcMapping[5].$name = "CONFIG_PRU_I2S_PRU1_ERR";
+pruicss1.intcMapping[5].event = "23";
+pruicss1.intcMapping[5].channel = "7";
diff --git a/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/main.c b/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/main.c
new file mode 100644
index 000000000..630d37f5e
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/main.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022-23 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+#include
+#include "ti_drivers_config.h"
+#include "ti_board_config.h"
+#include "FreeRTOS.h"
+#include "task.h"
+
+#define MAIN_TASK_PRI (configMAX_PRIORITIES-1)
+
+#define MAIN_TASK_SIZE (16384U/sizeof(configSTACK_DEPTH_TYPE))
+StackType_t gMainTaskStack[MAIN_TASK_SIZE] __attribute__((aligned(32)));
+
+StaticTask_t gMainTaskObj;
+TaskHandle_t gMainTask;
+
+void pru_i2s_diagnostic_main(void *args);
+
+void freertos_main(void *args)
+{
+ pru_i2s_diagnostic_main(NULL);
+
+ vTaskDelete(NULL);
+}
+
+
+int main(void)
+{
+ /* init SOC specific modules */
+ System_init();
+ Board_init();
+
+ /* This task is created at highest priority, it should create more tasks and then delete itself */
+ gMainTask = xTaskCreateStatic( freertos_main, /* Pointer to the function that implements the task. */
+ "freertos_main", /* Text name for the task. This is to facilitate debugging only. */
+ MAIN_TASK_SIZE, /* Stack depth in units of StackType_t typically uint32_t on 32b CPUs */
+ NULL, /* We are not using the task parameter. */
+ MAIN_TASK_PRI, /* task priority, 0 is lowest priority, configMAX_PRIORITIES-1 is highest */
+ gMainTaskStack, /* pointer to stack base */
+ &gMainTaskObj ); /* pointer to statically allocated task object memory */
+ configASSERT(gMainTask != NULL);
+
+ /* Start the scheduler to start the tasks executing. */
+ vTaskStartScheduler();
+
+ /* The following line should never be reached because vTaskStartScheduler()
+ will only return if there was not enough FreeRTOS heap memory available to
+ create the Idle and (if configured) Timer tasks. Heap management, and
+ techniques for trapping heap exhaustion, are described in the book text. */
+ DebugP_assertNoLog(0);
+
+ return 0;
+}
diff --git a/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec b/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec
new file mode 100644
index 000000000..0ae0cf6a0
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/example.projectspec
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile b/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile
new file mode 100644
index 000000000..991da82cd
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile
@@ -0,0 +1,387 @@
+#
+# Auto generated makefile
+#
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+include $(MCU_PLUS_SDK_PATH)/devconfig/devconfig.mak
+
+
+CG_TOOL_ROOT=$(CGT_TI_ARM_CLANG_PATH)
+
+CC=$(CG_TOOL_ROOT)/bin/tiarmclang
+LNK=$(CG_TOOL_ROOT)/bin/tiarmclang
+STRIP=$(CG_TOOL_ROOT)/bin/tiarmstrip
+OBJCOPY=$(CG_TOOL_ROOT)/bin/tiarmobjcopy
+COV=$(CG_TOOL_ROOT)/bin/tiarmcov
+PROFDATA=$(CG_TOOL_ROOT)/bin/tiarmprofdata
+COVERAGE_PATH=$(abspath .)
+ifeq ($(OS), Windows_NT)
+ PYTHON=python
+else
+ PYTHON=python3
+endif
+
+PROFILE?=release
+ConfigName:=$(PROFILE)
+
+OUTNAME:=pru_i2s_app.$(PROFILE).out
+
+BOOTIMAGE_PATH=$(abspath .)
+BOOTIMAGE_NAME:=pru_i2s_app.$(PROFILE).appimage
+BOOTIMAGE_NAME_XIP:=pru_i2s_app.$(PROFILE).appimage_xip
+BOOTIMAGE_NAME_SIGNED:=pru_i2s_app.$(PROFILE).appimage.signed
+BOOTIMAGE_NAME_MCELF:=pru_i2s_app.$(PROFILE).mcelf
+BOOTIMAGE_NAME_MCELF_HS:=pru_i2s_app.$(PROFILE).mcelf.hs
+BOOTIMAGE_RPRC_NAME:=pru_i2s_app.$(PROFILE).rprc
+BOOTIMAGE_RPRC_NAME_XIP:=pru_i2s_app.$(PROFILE).rprc_xip
+BOOTIMAGE_RPRC_NAME_TMP:=pru_i2s_app.$(PROFILE).rprc_tmp
+BOOTIMAGE_NAME_HS:=pru_i2s_app.$(PROFILE).appimage.hs
+BOOTIMAGE_NAME_HS_FS:=pru_i2s_app.$(PROFILE).appimage.hs_fs
+TARGETS := $(BOOTIMAGE_NAME)
+
+ifeq ($(DEVICE_TYPE), HS)
+ TARGETS += $(BOOTIMAGE_NAME_HS)
+endif
+
+FILES_common := \
+ pru_i2s_diagnostic.c \
+ pru_i2s_app_config.c \
+ main.c \
+ ti_drivers_config.c \
+ ti_drivers_open_close.c \
+ ti_board_config.c \
+ ti_board_open_close.c \
+ ti_dpl_config.c \
+ ti_pinmux_config.c \
+ ti_power_clock_config.c \
+
+FILES_PATH_common = \
+ .. \
+ ../../.. \
+ generated \
+
+INCLUDES_common := \
+ -I${CG_TOOL_ROOT}/include/c \
+ -I${MCU_PLUS_SDK_PATH}/source \
+ -I${OPEN_PRU_PATH}/source \
+ -I${OPEN_PRU_PATH}/examples/pru_i2s/include \
+ -I${OPEN_PRU_PATH}/examples/pru_i2s/firmware \
+ -I${OPEN_PRU_PATH}/examples/pru_i2s/pru_i2s_app \
+ -I${MCU_PLUS_SDK_PATH}/source/kernel/freertos/FreeRTOS-Kernel/include \
+ -I${MCU_PLUS_SDK_PATH}/source/kernel/freertos/portable/TI_ARM_CLANG/ARM_CR5F \
+ -I${MCU_PLUS_SDK_PATH}/source/kernel/freertos/config/am261x/r5f \
+ -I${MCU_PLUS_SDK_PATH}/source/pru_io/driver \
+ -Igenerated \
+
+DEFINES_common := \
+ -DSOC_AM261X \
+ -DOS_FREERTOS \
+
+CFLAGS_common := \
+ -mcpu=cortex-r5 \
+ -mfloat-abi=hard \
+ -mfpu=vfpv3-d16 \
+ -mthumb \
+ -Wall \
+ -Werror \
+ -g \
+ -Wno-gnu-variable-sized-type-not-at-end \
+ -Wno-unused-function \
+
+CFLAGS_cpp_common := \
+ -Wno-c99-designator \
+ -Wno-extern-c-compat \
+ -Wno-c++11-narrowing \
+ -Wno-reorder-init-list \
+ -Wno-register \
+ -Wno-writable-strings \
+ -Wno-enum-compare \
+ -Wno-reserved-user-defined-literal \
+ -Wno-unused-const-variable \
+ -Wno-vla-cxx-extension \
+ -x c++ \
+
+CFLAGS_debug := \
+ -D_DEBUG_=1 \
+
+CFLAGS_release := \
+ -Os \
+
+LNK_FILES_common = \
+ generated/linker.cmd \
+
+LIBS_PATH_common = \
+ -Wl,-i${MCU_PLUS_SDK_PATH}/source/kernel/freertos/lib \
+ -Wl,-i${MCU_PLUS_SDK_PATH}/source/drivers/lib \
+ -Wl,-i${MCU_PLUS_SDK_PATH}/source/board/lib \
+ -Wl,-i${MCU_PLUS_SDK_PATH}/source/pru_io/lib \
+ -Wl,-i${OPEN_PRU_PATH}/examples/pru_i2s/lib \
+ -Wl,-i${CG_TOOL_ROOT}/lib \
+
+LIBS_common = \
+ -lfreertos.am261x.r5f.ti-arm-clang.${ConfigName}.lib \
+ -ldrivers.am261x.r5f.ti-arm-clang.${ConfigName}.lib \
+ -lboard.am261x.r5f.ti-arm-clang.${ConfigName}.lib \
+ -lpru_i2s.am261x.r5f.ti-arm-clang.${ConfigName}.lib \
+ -llibc.a \
+ -llibsysbm.a \
+
+LFLAGS_common = \
+ -Wl,--diag_suppress=10063 \
+ -Wl,--ram_model \
+ -Wl,--reread_libs \
+
+
+LIBS_NAME = \
+ freertos.am261x.r5f.ti-arm-clang.${ConfigName}.lib \
+ drivers.am261x.r5f.ti-arm-clang.${ConfigName}.lib \
+ board.am261x.r5f.ti-arm-clang.${ConfigName}.lib \
+ pru_i2s.am261x.r5f.ti-arm-clang.${ConfigName}.lib \
+ libc.a \
+ libsysbm.a \
+
+LIBS_PATH_NAME = \
+ ${MCU_PLUS_SDK_PATH}/source/kernel/freertos/lib \
+ ${MCU_PLUS_SDK_PATH}/source/drivers/lib \
+ ${MCU_PLUS_SDK_PATH}/source/board/lib \
+ ${MCU_PLUS_SDK_PATH}/source/pru_io/lib \
+ ${OPEN_PRU_PATH}/examples/pru_i2s/lib \
+ ${CG_TOOL_ROOT}/lib \
+
+FILES := $(FILES_common) $(FILES_$(PROFILE))
+ASMFILES := $(ASMFILES_common) $(ASMFILES_$(PROFILE))
+FILES_PATH := $(FILES_PATH_common) $(FILES_PATH_$(PROFILE))
+CFLAGS := $(CFLAGS_common) $(CFLAGS_$(PROFILE))
+ifeq ($(INSTRUMENTATION_MODE), yes)
+CFLAGS += -fprofile-instr-generate -fcoverage-mapping
+endif
+DEFINES := $(DEFINES_common) $(DEFINES_$(PROFILE))
+INCLUDES := $(INCLUDES_common) $(INCLUDE_$(PROFILE))
+LIBS := $(LIBS_common) $(LIBS_$(PROFILE))
+LIBS_PATH := $(LIBS_PATH_common) $(LIBS_PATH_$(PROFILE))
+LFLAGS := $(LFLAGS_common) $(LFLAGS_$(PROFILE))
+LNKOPTFLAGS := $(LNKOPTFLAGS_common) $(LNKOPTFLAGS_$(PROFILE))
+LNK_FILES := $(LNK_FILES_common) $(LNK_FILES_$(PROFILE))
+
+OBJDIR := obj/$(PROFILE)/
+OBJS := $(FILES:%.c=%.obj)
+OBJS += $(ASMFILES:%.S=%.obj)
+DEPS := $(FILES:%.c=%.d)
+
+vpath %.obj $(OBJDIR)
+vpath %.c $(FILES_PATH)
+vpath %.S $(FILES_PATH)
+vpath %.lib $(LIBS_PATH_NAME)
+vpath %.a $(LIBS_PATH_NAME)
+
+$(OBJDIR)/%.obj %.obj: %.c
+ @echo Compiling: am261x:r5fss0-0:freertos:ti-arm-clang $(OUTNAME): $<
+ $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) -MMD -o $(OBJDIR)/$@ $<
+
+$(OBJDIR)/%.obj %.obj: %.S
+ @echo Compiling: am261x:r5fss0-0:freertos:ti-arm-clang $(LIBNAME): $<
+ $(CC) -c $(CFLAGS) -o $(OBJDIR)/$@ $<
+
+all: build_lib_if_needed $(TARGETS)
+
+build_lib_if_needed:
+ @echo "Library is built by parent makefile"
+
+SYSCFG_GEN_FILES=generated/ti_drivers_config.c generated/ti_drivers_config.h
+SYSCFG_GEN_FILES+=generated/ti_drivers_open_close.c generated/ti_drivers_open_close.h
+SYSCFG_GEN_FILES+=generated/ti_dpl_config.c generated/ti_dpl_config.h
+SYSCFG_GEN_FILES+=generated/ti_pinmux_config.c generated/ti_power_clock_config.c
+SYSCFG_GEN_FILES+=generated/ti_board_config.c generated/ti_board_config.h
+SYSCFG_GEN_FILES+=generated/ti_board_open_close.c generated/ti_board_open_close.h
+
+SYSTEM_FLAG ?= false
+
+ifeq ($(SYSTEM_FLAG), false)
+ SYSTEM_COMMAND := syscfg $(SYSCFG_GEN_FILES) $(OBJS) $(LNK_FILES) $(LIBS_NAME)
+else
+ SYSTEM_COMMAND := $(OBJS) $(LNK_FILES) $(LIBS_NAME)
+endif
+
+# Library is built by parent makefile (top-level pru_i2s/makefile)
+pru_i2s.am261x.r5f.ti-arm-clang.$(PROFILE).lib:
+ @echo "Building library via parent makefile..."
+ $(MAKE) -C ../../../.. build_lib_am261x
+
+FORCE:
+
+$(OUTNAME): $(SYSTEM_COMMAND)
+ @echo .
+ @echo Linking: am261x:r5fss0-0:freertos:ti-arm-clang $@ ...
+ $(LNK) $(LNKOPTFLAGS) $(LFLAGS) $(LIBS_PATH) -Wl,-m=$(basename $@).map -o $@ $(addprefix $(OBJDIR), $(OBJS)) $(LIBS) $(LNK_FILES)
+ @echo Linking: am261x:r5fss0-0:freertos:ti-arm-clang $@ Done !!!
+ @echo .
+
+clean:
+ @echo Cleaning: am261x:r5fss0-0:freertos:ti-arm-clang $(OUTNAME) ...
+ $(RMDIR) $(OBJDIR)
+ $(RM) $(OUTNAME)
+ $(RM) $(BOOTIMAGE_NAME)
+ $(RM) $(BOOTIMAGE_NAME_XIP)
+ $(RM) $(BOOTIMAGE_NAME_SIGNED)
+ $(RM) $(BOOTIMAGE_RPRC_NAME)
+ $(RM) $(BOOTIMAGE_RPRC_NAME_XIP)
+ $(RM) $(BOOTIMAGE_NAME_MCELF)
+ $(RMDIR) generated/
+
+scrub:
+ @echo Scrubing: am261x:r5fss0-0:freertos:ti-arm-clang pru_i2s_app ...
+ $(RMDIR) obj
+ifeq ($(OS),Windows_NT)
+ $(RM) \*.out
+ $(RM) \*.map
+ $(RM) \*.appimage*
+ $(RM) \*.rprc*
+ $(RM) \*.tiimage*
+ $(RM) \*.bin
+ $(RM) \*.mcelf
+ $(RM) \*.mcelf_xip
+ $(RM) \*.mcelf-enc
+ $(RM) \*.mcelf.hs
+else
+ $(RM) *.out
+ $(RM) *.map
+ $(RM) *.appimage*
+ $(RM) *.rprc*
+ $(RM) *.tiimage*
+ $(RM) *.bin
+ $(RM) *.mcelf
+ $(RM) *.mcelf_xip
+ $(RM) *.mcelf-enc
+ $(RM) *.mcelf.hs
+endif
+ $(RMDIR) generated
+
+$(OBJS): | $(OBJDIR)
+
+$(OBJDIR):
+ $(MKDIR) $@
+
+
+.NOTPARALLEL:
+
+.INTERMEDIATE: syscfg
+$(SYSCFG_GEN_FILES): syscfg
+
+ifeq ($(SYSTEM_FLAG), false)
+syscfg: ../example.syscfg
+ @echo Generating SysConfig files ...
+ $(SYSCFG_NODE) $(SYSCFG_CLI_PATH)/dist/cli.js --product $(SYSCFG_SDKPRODUCT) --product $(SYSCFG_MCU_PLUS_SDK_PRODUCT) --context r5fss0-0 --part AM2612 --package ZFG --output generated/ ../example.syscfg
+endif
+
+syscfg-gui:
+ $(SYSCFG_NWJS) $(SYSCFG_PATH) --product $(SYSCFG_SDKPRODUCT) --product $(SYSCFG_MCU_PLUS_SDK_PRODUCT) --device AM261x_ZFG --context r5fss0-0 --part AM2612 --package ZFG --output generated/ ../example.syscfg
+
+#
+# Generation of boot image which can be loaded by Secondary Boot Loader (SBL)
+#
+ifeq ($(OS),Windows_NT)
+EXE_EXT=.exe
+endif
+ifeq ($(OS),Windows_NT)
+ BOOTIMAGE_CERT_GEN_CMD=powershell -executionpolicy unrestricted -command $(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/x509CertificateGen.ps1
+else
+ BOOTIMAGE_CERT_GEN_CMD=$(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/x509CertificateGen.sh
+endif
+BOOTIMAGE_TEMP_OUT_FILE=temp_stdout_$(PROFILE).txt
+
+
+BOOTIMAGE_CORE_ID_r5fss0-0 = 0
+BOOTIMAGE_CORE_ID_r5fss0-1 = 1
+BOOTIMAGE_CORE_ID_r5fss1-0 = 2
+BOOTIMAGE_CORE_ID_r5fss1-1 = 3
+SBL_RUN_ADDRESS=0x70002000
+SBL_DEV_ID=55
+
+MULTI_CORE_IMAGE_GEN = $(SYSCFG_NODE) $(MCU_PLUS_SDK_PATH)/tools/boot/multicoreImageGen/multicoreImageGen.js
+OUTRPRC_CMD = $(SYSCFG_NODE) $(MCU_PLUS_SDK_PATH)/tools/boot/out2rprc/elf2rprc.js
+APP_IMAGE_SIGN_CMD = $(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/mcu_appimage_x509_cert_gen.py
+MCELF_IMAGE_GEN = $(MCU_PLUS_SDK_PATH)/tools/boot/multicore-elf/genimage.py
+
+ifeq ($(OS),Windows_NT)
+ XIPGEN_CMD=$(MCU_PLUS_SDK_PATH)/tools/boot/xipGen/xipGen.exe
+else
+ UNAME_S = $(shell uname -s)
+ ifeq ($(UNAME_S), Darwin)
+ XIPGEN_CMD=$(MCU_PLUS_SDK_PATH)/tools/boot/xipGen/xipGen.out.mac
+ else
+ XIPGEN_CMD=$(MCU_PLUS_SDK_PATH)/tools/boot/xipGen/xipGen.out
+endif
+endif
+
+MULTI_CORE_IMAGE_PARAMS = \
+ $(BOOTIMAGE_RPRC_NAME)@$(BOOTIMAGE_CORE_ID_r5fss0-0) \
+
+MULTI_CORE_IMAGE_PARAMS_XIP = \
+ $(BOOTIMAGE_RPRC_NAME_XIP)@$(BOOTIMAGE_CORE_ID_r5fss0-0) \
+
+$(BOOTIMAGE_NAME): $(OUTNAME)
+ @echo Boot image: am261x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_PATH)/$@ ...
+ifneq ($(OS),Windows_NT)
+ $(CHMOD) a+x $(XIPGEN_CMD)
+endif
+ $(OUTRPRC_CMD) $(OUTNAME) >> $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(COPY) $(BOOTIMAGE_RPRC_NAME) $(BOOTIMAGE_RPRC_NAME_TMP)
+ $(RM) $(BOOTIMAGE_RPRC_NAME)
+ $(XIPGEN_CMD) -i $(BOOTIMAGE_RPRC_NAME_TMP) -o $(BOOTIMAGE_RPRC_NAME) -x $(BOOTIMAGE_RPRC_NAME_XIP) --flash-start-addr 0x60000000 -v > $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(MULTI_CORE_IMAGE_GEN) --devID $(SBL_DEV_ID) --out $(BOOTIMAGE_NAME) $(MULTI_CORE_IMAGE_PARAMS) >> $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(MULTI_CORE_IMAGE_GEN) --devID $(SBL_DEV_ID) --out $(BOOTIMAGE_NAME_XIP) $(MULTI_CORE_IMAGE_PARAMS_XIP) >> $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(RM) $(BOOTIMAGE_RPRC_NAME_TMP)
+ $(RM) $(BOOTIMAGE_TEMP_OUT_FILE)
+ @echo Boot image: am261x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_PATH)/$@ Done !!!
+ @echo Boot MulticoreELF image: $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_MCELF) ...
+ $(PYTHON) $(MCELF_IMAGE_GEN) --core-img=$(BOOTIMAGE_CORE_ID_r5fss0-0):$(OUTNAME) --output=$(BOOTIMAGE_NAME_MCELF) --merge-segments=$(MCELF_MERGE_SEGMENTS_FLAG) --tolerance-limit=$(MCELF_MERGE_SEGMENTS_TOLERANCE_LIMIT) --ignore-context=$(MCELF_IGNORE_CONTEXT_FLAG) --xip=$(MCELF_XIP_RANGE) --xlat=$(MCELF_ADDR_TRANSLATION_PATH) --max-segment-size=$(MCELF_MAX_SEGMENT_SIZE)
+ @echo Boot MulticoreELF ELF image: $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_MCELF) Done !!!
+ @echo .
+
+$(BOOTIMAGE_NAME_HS): $(BOOTIMAGE_NAME)
+ifeq ($(DEVICE_TYPE), HS)
+# Sign the appimage using appimage signing script
+ifeq ($(ENC_ENABLED),no)
+ifeq ($(RSASSAPSS_ENABLED),no)
+ @echo Boot image signing: Encryption is disabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_HS)
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_MCELF_HS)
+else
+ @echo Boot image signing: Encryption is disabled. RSASSAPSS is enabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_HS) --rsassa_pss
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_MCELF_HS) --rsassa_pss
+endif
+else
+ifeq ($(RSASSAPSS_ENABLED),no)
+ @echo Boot image signing: Encryption is enabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_HS)
+ $(RM) $(BOOTIMAGE_NAME)-enc
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_MCELF_HS)
+ $(RM) $(BOOTIMAGE_NAME_MCELF)-enc
+else
+ @echo Boot image signing: Encryption is enabled. RSASSAPSS is enabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_HS) --rsassa_pss
+ $(RM) $(BOOTIMAGE_NAME)-enc
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_MCELF_HS) --rsassa_pss
+ $(RM) $(BOOTIMAGE_NAME_MCELF)-enc
+endif
+endif
+ @echo Boot image: am261x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_HS) Done !!!
+ @echo Boot image: am261x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_MCELF_HS) Done !!!
+ @echo .
+endif
+
+
+
+.PHONY: coverage
+coverage:
+ @echo Creating Coverage Report for pru_i2s_app.$(PROFILE) ...
+ $(MKDIR) coverage
+ $(PROFDATA) merge -sparse -obj-file=$(OUTNAME) $(OUTNAME).cnt -o pru_i2s_app.$(PROFILE).profdata
+ $(COV) show --format=html --show-expansions --show-instantiations --show-branches=count --object=$(OUTNAME) -instr-profile=pru_i2s_app.$(PROFILE).profdata --output-dir=$(COVERAGE_PATH)/coverage --ignore-filename-regex=build_jenkins
+ $(COV) export --format=text --object=$(OUTNAME) --instr-profile=pru_i2s_app.$(PROFILE).profdata > coverage/pru_i2s_app.$(PROFILE).profdata.json
+ node $(MCU_PLUS_SDK_PATH)/tools/smart_placement/clang_coverage_analyse.js --input=coverage/pru_i2s_app.$(PROFILE).profdata.json --output-json=coverage/pru_i2s_app.$(PROFILE).analysis.json --output=../pru_i2s_app.annotations.$(PROFILE).S --top-function-count=500
+ @echo Coverage Report Generated at $(COVERAGE_PATH)/coverage folder !!!
+
+-include $(addprefix $(OBJDIR)/, $(DEPS))
diff --git a/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_ccs_bootimage_gen b/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_ccs_bootimage_gen
new file mode 100644
index 000000000..0b1dbf584
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_ccs_bootimage_gen
@@ -0,0 +1,141 @@
+#
+# Auto generated makefile
+#
+
+# Below variables need to be defined outside this file or via command line
+# - OPEN_PRU_PATH
+# - MCU_PLUS_SDK_PATH
+# - PROFILE
+# - CG_TOOL_ROOT
+# - OUTNAME
+# - CCS_INSTALL_DIR
+# - CCS_IDE_MODE
+
+CCS_PATH=$(CCS_INSTALL_DIR)
+include $(OPEN_PRU_PATH)/imports.mak
+include $(MCU_PLUS_SDK_PATH)/devconfig/devconfig.mak
+
+STRIP=$(CG_TOOL_ROOT)/bin/tiarmstrip
+OBJCOPY=$(CG_TOOL_ROOT)/bin/tiarmobjcopy
+ifeq ($(OS), Windows_NT)
+ PYTHON=python
+else
+ PYTHON=python3
+endif
+
+OUTFILE=$(PROFILE)/$(OUTNAME).out
+BOOTIMAGE_PATH=$(abspath ${PROFILE})
+BOOTIMAGE_NAME:=$(BOOTIMAGE_PATH)/$(OUTNAME).appimage
+BOOTIMAGE_NAME_XIP:=$(BOOTIMAGE_PATH)/$(OUTNAME).appimage_xip
+BOOTIMAGE_NAME_SIGNED:=$(BOOTIMAGE_PATH)/$(OUTNAME).appimage.signed
+BOOTIMAGE_RPRC_NAME:=$(BOOTIMAGE_PATH)/$(OUTNAME).rprc
+BOOTIMAGE_RPRC_NAME_XIP:=$(BOOTIMAGE_PATH)/$(OUTNAME).rprc_xip
+BOOTIMAGE_RPRC_NAME_TMP:=$(BOOTIMAGE_PATH)/$(OUTNAME).rprc_tmp
+BOOTIMAGE_NAME_MCELF:=$(BOOTIMAGE_PATH)/$(OUTNAME).mcelf
+BOOTIMAGE_NAME_MCELF_HS:=$(BOOTIMAGE_PATH)/$(OUTNAME).mcelf.hs
+BOOTIMAGE_NAME_HS:=$(BOOTIMAGE_PATH)/pru_i2s_app.$(PROFILE).appimage.hs
+BOOTIMAGE_NAME_HS_FS:=$(BOOTIMAGE_PATH)/pru_i2s_app.$(PROFILE).appimage.hs_fs
+TARGETS := $(BOOTIMAGE_NAME)
+TARGETS += $(BOOTIMAGE_NAME_MCELF)
+TARGETS += $(BOOTIMAGE_NAME_MCELF_HS)
+ifeq ($(DEVICE_TYPE), HS)
+ TARGETS += $(BOOTIMAGE_NAME_HS)
+endif
+
+#
+# Generation of boot image which can be loaded by Secondary Boot Loader (SBL)
+#
+ifeq ($(OS),Windows_NT)
+EXE_EXT=.exe
+endif
+ifeq ($(OS),Windows_NT)
+ BOOTIMAGE_CERT_GEN_CMD=powershell -executionpolicy unrestricted -command $(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/x509CertificateGen.ps1
+else
+ BOOTIMAGE_CERT_GEN_CMD=$(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/x509CertificateGen.sh
+endif
+BOOTIMAGE_TEMP_OUT_FILE=$(PROFILE)/temp_stdout_$(PROFILE).txt
+
+BOOTIMAGE_CORE_ID_r5fss0-0 = 0
+BOOTIMAGE_CORE_ID_r5fss0-1 = 1
+BOOTIMAGE_CORE_ID_r5fss1-0 = 2
+BOOTIMAGE_CORE_ID_r5fss1-1 = 3
+SBL_RUN_ADDRESS=0x70002000
+SBL_DEV_ID=55
+
+MULTI_CORE_IMAGE_GEN = $(CCS_NODE) $(MCU_PLUS_SDK_PATH)/tools/boot/multicoreImageGen/multicoreImageGen.js
+OUTRPRC_CMD = $(CCS_NODE) $(MCU_PLUS_SDK_PATH)/tools/boot/out2rprc/elf2rprc.js
+APP_IMAGE_SIGN_CMD = $(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/mcu_appimage_x509_cert_gen.py
+MCELF_IMAGE_GEN = $(MCU_PLUS_SDK_PATH)/tools/boot/multicore-elf/genimage.py
+
+ifeq ($(OS),Windows_NT)
+ XIPGEN_CMD=$(MCU_PLUS_SDK_PATH)/tools/boot/xipGen/xipGen.exe
+else
+ UNAME_S = $(shell uname -s)
+ ifeq ($(UNAME_S), Darwin)
+ XIPGEN_CMD=$(MCU_PLUS_SDK_PATH)/tools/boot/xipGen/xipGen.out.mac
+ else
+ XIPGEN_CMD=$(MCU_PLUS_SDK_PATH)/tools/boot/xipGen/xipGen.out
+endif
+endif
+
+MULTI_CORE_IMAGE_PARAMS = \
+ $(BOOTIMAGE_RPRC_NAME)@$(BOOTIMAGE_CORE_ID_r5fss0-0) \
+
+MULTI_CORE_IMAGE_PARAMS_XIP = \
+ $(BOOTIMAGE_RPRC_NAME_XIP)@$(BOOTIMAGE_CORE_ID_r5fss0-0) \
+
+all:
+ifeq ($(CCS_IDE_MODE),cloud)
+# No post build steps
+else
+ @echo Boot image: am261x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_NAME) ...
+ $(OUTRPRC_CMD) $(OUTFILE) >> $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(COPY) $(OUTNAME).rprc $(BOOTIMAGE_RPRC_NAME)
+ $(COPY) $(BOOTIMAGE_RPRC_NAME) $(BOOTIMAGE_RPRC_NAME_TMP)
+ $(RM) $(BOOTIMAGE_RPRC_NAME)
+ $(XIPGEN_CMD) -i $(BOOTIMAGE_RPRC_NAME_TMP) -o $(BOOTIMAGE_RPRC_NAME) -x $(BOOTIMAGE_RPRC_NAME_XIP) --flash-start-addr 0x60000000 -v > $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(MULTI_CORE_IMAGE_GEN) --devID $(SBL_DEV_ID) --out $(BOOTIMAGE_NAME) $(MULTI_CORE_IMAGE_PARAMS) >> $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(MULTI_CORE_IMAGE_GEN) --devID $(SBL_DEV_ID) --out $(BOOTIMAGE_NAME_XIP) $(MULTI_CORE_IMAGE_PARAMS_XIP) >> $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(RM) $(BOOTIMAGE_RPRC_NAME_TMP)
+
+ @echo Boot multi-core ELF image: am261x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_NAME_MCELF) ...
+
+ $(PYTHON) $(MCELF_IMAGE_GEN) --core-img=$(BOOTIMAGE_CORE_ID_r5fss0-0):$(OUTFILE) --output=$(BOOTIMAGE_NAME_MCELF) --merge-segments=$(MCELF_MERGE_SEGMENTS_FLAG) --tolerance-limit=$(MCELF_MERGE_SEGMENTS_TOLERANCE_LIMIT) --ignore-context=$(MCELF_IGNORE_CONTEXT_FLAG) --xip=$(MCELF_XIP_RANGE) --xlat=$(MCELF_ADDR_TRANSLATION_PATH) --max_segment_size=$(MCELF_MAX_SEGMENT_SIZE)
+
+ @echo Boot multi-core ELF image: $(BOOTIMAGE_NAME_MCELF) Done !!!
+ @echo .
+
+ @echo Boot image: am261x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_NAME) Done !!!
+ @echo .
+ifeq ($(DEVICE_TYPE), HS)
+# Sign the appimage using appimage signing script
+ifeq ($(ENC_ENABLED),no)
+ifeq ($(RSASSAPSS_ENABLED),no)
+ @echo Boot image signing: Encryption is disabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_HS)
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_MCELF_HS)
+else
+ @echo Boot image signing: Encryption is disabled. RSASSA-PSS is enabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_HS) --rsassa_pss
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_MCELF_HS) --rsassa_pss
+endif
+else
+ifeq ($(RSASSAPSS_ENABLED),no)
+ @echo Boot image signing: Encryption is enabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_HS)
+ $(RM) $(BOOTIMAGE_NAME)-enc
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_MCELF_HS)
+ $(RM) $(BOOTIMAGE_NAME_MCELF)-enc
+else
+ @echo Boot image signing: Encryption is enabled. RSASSA-PSS is enabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_HS) --rsassa_pss
+ $(RM) $(BOOTIMAGE_NAME)-enc
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_MCELF_HS) --rsassa_pss
+ $(RM) $(BOOTIMAGE_NAME_MCELF)-enc
+endif
+endif
+ @echo Boot image: am261x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_HS) Done !!!
+ @echo Boot image: am261x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_MCELF_HS) Done !!!
+ @echo .
+endif
+endif
diff --git a/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_projectspec b/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_projectspec
new file mode 100644
index 000000000..8d2e5ecf3
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/makefile_projectspec
@@ -0,0 +1,20 @@
+#
+# Auto generated makefile
+#
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+
+PROFILE?=Release
+
+PROJECT_NAME=pru_i2s_app_am261x-lp_r5fss0-0_freertos_ti-arm-clang
+
+all:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE)
+
+clean:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) -ccs.clean
+
+export:
+ $(MKDIR) $(OPEN_PRU_PATH)/ccs_projects
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectCreate -ccs.projectSpec example.projectspec -ccs.overwrite full
diff --git a/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/syscfg_c.rov.xs b/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/syscfg_c.rov.xs
new file mode 100644
index 000000000..472ab3849
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/am261x-lp/r5fss0-0_freertos/ti-arm-clang/syscfg_c.rov.xs
@@ -0,0 +1,8 @@
+/*
+ * ======== syscfg_c.rov.xs ========
+ * This file contains the information needed by the Runtime Object
+ * View (ROV) tool.
+ */
+var crovFiles = [
+ "kernel/freertos/rov/FreeRTOS.rov.js",
+];
diff --git a/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/example.syscfg b/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/example.syscfg
new file mode 100644
index 000000000..04aba81c2
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/example.syscfg
@@ -0,0 +1,372 @@
+/**
+ * These arguments were used when this file was generated. They will be automatically applied on subsequent loads
+ * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments.
+ * @cliArgs --device "AM263x_beta" --part "AM263x" --package "ZCZ" --context "r5fss0-0" --product "OPEN_PRU@07.03.01" --product "MCU_PLUS_SDK_AM263x@10.02.00"
+ * @v2CliArgs --device "AM2634" --package "NFBGA (ZCZ)" --context "r5fss0-0" --product "OPEN_PRU@07.03.01" --product "MCU_PLUS_SDK_AM263x@10.02.00"
+ * @versions {"tool":"1.25.0+4268"}
+ */
+
+/**
+ * Import the modules used in this configuration.
+ */
+const gpio = scripting.addModule("/drivers/gpio/gpio", {}, false);
+const gpio1 = gpio.addInstance();
+const gpio2 = gpio.addInstance();
+const i2c = scripting.addModule("/drivers/i2c/i2c", {}, false);
+const i2c1 = i2c.addInstance();
+const pruicss = scripting.addModule("/drivers/pruicss/pruicss", {}, false);
+const pruicss1 = pruicss.addInstance();
+const debug_log = scripting.addModule("/kernel/dpl/debug_log");
+const mpu_armv7 = scripting.addModule("/kernel/dpl/mpu_armv7", {}, false);
+const mpu_armv71 = mpu_armv7.addInstance();
+const mpu_armv72 = mpu_armv7.addInstance();
+const mpu_armv73 = mpu_armv7.addInstance();
+const mpu_armv74 = mpu_armv7.addInstance();
+const mpu_armv75 = mpu_armv7.addInstance();
+const mpu_armv76 = mpu_armv7.addInstance();
+const mpu_armv77 = mpu_armv7.addInstance();
+const mpu_armv78 = mpu_armv7.addInstance();
+const default_linker = scripting.addModule("/memory_configurator/default_linker", {}, false);
+const default_linker1 = default_linker.addInstance();
+const general = scripting.addModule("/memory_configurator/general", {}, false);
+const general1 = general.addInstance();
+const region = scripting.addModule("/memory_configurator/region", {}, false);
+const region1 = region.addInstance();
+const section = scripting.addModule("/memory_configurator/section", {}, false);
+const section1 = section.addInstance();
+const section2 = section.addInstance();
+const section3 = section.addInstance();
+const section4 = section.addInstance();
+const section5 = section.addInstance();
+const section6 = section.addInstance();
+const section7 = section.addInstance();
+const section8 = section.addInstance();
+const section9 = section.addInstance();
+const section10 = section.addInstance();
+const section11 = section.addInstance();
+const section12 = section.addInstance();
+const section13 = section.addInstance();
+
+/**
+ * Write custom configuration values to the imported modules.
+ */
+gpio1.$name = "CONFIG_GPIO_DEBUG0";
+gpio1.pinDir = "OUTPUT";
+gpio1.rx = true;
+gpio1.GPIO_n.$assign = "EPWM0_A";
+
+gpio2.$name = "CONFIG_GPIO_DEBUG1";
+gpio2.pinDir = "OUTPUT";
+gpio2.rx = true;
+gpio2.GPIO_n.$assign = "EPWM0_B";
+
+i2c1.$name = "CONFIG_I2C2";
+i2c1.enableIntr = false;
+i2c1.I2C.$assign = "I2C2";
+i2c1.I2C.SCL.$assign = "UART0_RTSn";
+i2c1.I2C_child.$name = "drivers_i2c_v1_i2c_v1_template0";
+
+pruicss1.$name = "CONFIG_PRU_ICSS0";
+pruicss1.instance = "ICSSM0";
+pruicss1.AdditionalICSSSettings[0].$name = "CONFIG_PRU_ICSS_IO0";
+pruicss1.AdditionalICSSSettings[0].PruGPIO.create(1);
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].$name = "CONFIG_PRU_ICSS_GPIO0";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO5.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO6.rx = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO6.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO4.rx = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO4.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO0.rx = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO0.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO1.rx = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO1.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO2.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO3.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO5.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO6.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO4.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO0.rx = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO0.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO1.rx = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO1.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO2.rx = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO2.$used = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO3.rx = true;
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO3.$used = true;
+pruicss1.intcMapping.create(6);
+pruicss1.intcMapping[0].$name = "CONFIG_PRU_I2S_PRU0_TX";
+pruicss1.intcMapping[0].event = "18";
+pruicss1.intcMapping[0].channel = "2";
+pruicss1.intcMapping[1].$name = "CONFIG_PRU_I2S_PRU0_RX";
+pruicss1.intcMapping[1].event = "19";
+pruicss1.intcMapping[1].channel = "3";
+pruicss1.intcMapping[2].$name = "CONFIG_PRU_I2S_PRU0_ERR";
+pruicss1.intcMapping[2].event = "20";
+pruicss1.intcMapping[2].channel = "4";
+pruicss1.intcMapping[3].$name = "CONFIG_PRU_I2S_PRU1_TX";
+pruicss1.intcMapping[3].event = "21";
+pruicss1.intcMapping[3].channel = "5";
+pruicss1.intcMapping[4].$name = "CONFIG_PRU_I2S_PRU1_RX";
+pruicss1.intcMapping[4].event = "22";
+pruicss1.intcMapping[4].channel = "6";
+pruicss1.intcMapping[5].$name = "CONFIG_PRU_I2S_PRU1_ERR";
+pruicss1.intcMapping[5].event = "23";
+pruicss1.intcMapping[5].channel = "7";
+
+mpu_armv71.$name = "CONFIG_MPU_REGION0";
+mpu_armv71.size = 31;
+mpu_armv71.attributes = "Device";
+mpu_armv71.accessPermissions = "Supervisor RD+WR, User RD";
+mpu_armv71.allowExecute = false;
+
+mpu_armv72.$name = "CONFIG_MPU_REGION1";
+mpu_armv72.size = 15;
+mpu_armv72.accessPermissions = "Supervisor RD+WR, User RD";
+
+mpu_armv73.$name = "CONFIG_MPU_REGION2";
+mpu_armv73.baseAddr = 0x80000;
+mpu_armv73.size = 15;
+mpu_armv73.accessPermissions = "Supervisor RD+WR, User RD";
+
+mpu_armv74.$name = "CONFIG_MPU_REGION3";
+mpu_armv74.accessPermissions = "Supervisor RD+WR, User RD";
+mpu_armv74.baseAddr = 0x70000000;
+mpu_armv74.size = 21;
+
+mpu_armv75.$name = "CONFIG_MPU_REGION4";
+mpu_armv75.size = 14;
+mpu_armv75.baseAddr = 0x50D00000;
+mpu_armv75.allowExecute = false;
+mpu_armv75.attributes = "Device";
+
+mpu_armv76.$name = "CONFIG_MPU_REGION5";
+mpu_armv76.size = 14;
+mpu_armv76.allowExecute = false;
+mpu_armv76.attributes = "Device";
+mpu_armv76.baseAddr = 0x72000000;
+
+mpu_armv77.$name = "CONFIG_MPU_REGION6";
+mpu_armv77.baseAddr = 0x700C0000;
+mpu_armv77.size = 18;
+mpu_armv77.attributes = "Cached+Sharable";
+mpu_armv77.allowExecute = false;
+
+mpu_armv78.$name = "CONFIG_MPU_REGION7";
+mpu_armv78.baseAddr = 0x48010000;
+mpu_armv78.size = 15;
+mpu_armv78.attributes = "Cached+Sharable";
+mpu_armv78.allowExecute = false;
+
+default_linker1.$name = "memory_configurator_default_linker0";
+
+general1.$name = "CONFIG_GENERAL0";
+general1.linker.$name = "TIARMCLANG0";
+
+region1.$name = "MEMORY_REGION_CONFIGURATION0";
+region1.memory_region.create(11);
+region1.memory_region[0].type = "TCMA";
+region1.memory_region[0].$name = "R5F_VECS";
+region1.memory_region[0].size = 0x40;
+region1.memory_region[0].auto = false;
+region1.memory_region[1].type = "TCMA";
+region1.memory_region[1].$name = "R5F_TCMA";
+region1.memory_region[1].size = 0x7FC0;
+region1.memory_region[2].type = "TCMB";
+region1.memory_region[2].size = 0x8000;
+region1.memory_region[2].$name = "R5F_TCMB";
+region1.memory_region[3].$name = "OCRAM";
+region1.memory_region[3].auto = false;
+region1.memory_region[3].size = 0x40000;
+region1.memory_region[3].manualStartAddress = 0x70080000;
+region1.memory_region[4].type = "FLASH";
+region1.memory_region[4].auto = false;
+region1.memory_region[4].size = 0x80000;
+region1.memory_region[4].$name = "FLASH";
+region1.memory_region[5].$name = "USER_SHM_MEM";
+region1.memory_region[5].auto = false;
+region1.memory_region[5].manualStartAddress = 0x701D0000;
+region1.memory_region[5].size = 0x4000;
+region1.memory_region[5].isShared = true;
+region1.memory_region[5].shared_cores = ["r5fss0-1","r5fss1-0","r5fss1-1"];
+region1.memory_region[6].$name = "LOG_SHM_MEM";
+region1.memory_region[6].auto = false;
+region1.memory_region[6].manualStartAddress = 0x701D4000;
+region1.memory_region[6].size = 0x4000;
+region1.memory_region[6].isShared = true;
+region1.memory_region[6].shared_cores = ["r5fss0-1","r5fss1-0","r5fss1-1"];
+region1.memory_region[7].type = "CUSTOM";
+region1.memory_region[7].$name = "RTOS_NORTOS_IPC_SHM_MEM";
+region1.memory_region[7].auto = false;
+region1.memory_region[7].manualStartAddress = 0x72000000;
+region1.memory_region[7].size = 0x3E80;
+region1.memory_region[7].isShared = true;
+region1.memory_region[7].shared_cores = ["r5fss0-1","r5fss1-0","r5fss1-1"];
+region1.memory_region[8].auto = false;
+region1.memory_region[8].size = 0x7F00;
+region1.memory_region[8].type = "CUSTOM";
+region1.memory_region[8].$name = "ICSSM_SHMEM";
+region1.memory_region[8].manualStartAddress = 0x48010100;
+region1.memory_region[9].size = 0x40000;
+region1.memory_region[9].auto = false;
+region1.memory_region[9].manualStartAddress = 0x700C0000;
+region1.memory_region[9].$name = "OCRAM_256K3_RAM";
+region1.memory_region[10].auto = false;
+region1.memory_region[10].manualStartAddress = 0x70100000;
+region1.memory_region[10].$name = "OCRAM_256K4_RAM";
+region1.memory_region[10].size = 0xD0000;
+
+section1.load_memory = "R5F_VECS";
+section1.group = false;
+section1.$name = "Vector Table";
+section1.output_section.create(1);
+section1.output_section[0].$name = ".vectors";
+section1.output_section[0].palignment = true;
+
+section2.load_memory = "OCRAM";
+section2.$name = "Text Segments";
+section2.output_section.create(5);
+section2.output_section[0].$name = ".text.hwi";
+section2.output_section[0].palignment = true;
+section2.output_section[1].$name = ".text.cache";
+section2.output_section[1].palignment = true;
+section2.output_section[2].$name = ".text.mpu";
+section2.output_section[2].palignment = true;
+section2.output_section[3].$name = ".text.boot";
+section2.output_section[3].palignment = true;
+section2.output_section[4].$name = ".text:abort";
+section2.output_section[4].palignment = true;
+
+section3.load_memory = "OCRAM";
+section3.$name = "Code and Read-Only Data";
+section3.output_section.create(2);
+section3.output_section[0].$name = ".text";
+section3.output_section[0].palignment = true;
+section3.output_section[1].$name = ".rodata";
+section3.output_section[1].palignment = true;
+
+section4.load_memory = "OCRAM";
+section4.$name = "Data Segment";
+section4.output_section.create(1);
+section4.output_section[0].$name = ".data";
+section4.output_section[0].palignment = true;
+
+section5.load_memory = "OCRAM";
+section5.$name = "Memory Segments";
+section5.output_section.create(3);
+section5.output_section[0].$name = ".bss";
+section5.output_section[0].output_sections_start = "__BSS_START";
+section5.output_section[0].output_sections_end = "__BSS_END";
+section5.output_section[0].palignment = true;
+section5.output_section[1].$name = ".sysmem";
+section5.output_section[1].palignment = true;
+section5.output_section[2].$name = ".stack";
+section5.output_section[2].palignment = true;
+
+section6.load_memory = "OCRAM";
+section6.$name = "Stack Segments";
+section6.output_section.create(5);
+section6.output_section[0].$name = ".irqstack";
+section6.output_section[0].output_sections_start = "__IRQ_STACK_START";
+section6.output_section[0].output_sections_end = "__IRQ_STACK_END";
+section6.output_section[0].input_section.create(1);
+section6.output_section[0].input_section[0].$name = ". = . + __IRQ_STACK_SIZE;";
+section6.output_section[1].$name = ".fiqstack";
+section6.output_section[1].output_sections_start = "__FIQ_STACK_START";
+section6.output_section[1].output_sections_end = "__FIQ_STACK_END";
+section6.output_section[1].input_section.create(1);
+section6.output_section[1].input_section[0].$name = ". = . + __FIQ_STACK_SIZE;";
+section6.output_section[2].$name = ".svcstack";
+section6.output_section[2].output_sections_start = "__SVC_STACK_START";
+section6.output_section[2].output_sections_end = "__SVC_STACK_END";
+section6.output_section[2].input_section.create(1);
+section6.output_section[2].input_section[0].$name = ". = . + __SVC_STACK_SIZE;";
+section6.output_section[3].$name = ".abortstack";
+section6.output_section[3].output_sections_start = "__ABORT_STACK_START";
+section6.output_section[3].output_sections_end = "__ABORT_STACK_END";
+section6.output_section[3].input_section.create(1);
+section6.output_section[3].input_section[0].$name = ". = . + __ABORT_STACK_SIZE;";
+section6.output_section[4].$name = ".undefinedstack";
+section6.output_section[4].output_sections_start = "__UNDEFINED_STACK_START";
+section6.output_section[4].output_sections_end = "__UNDEFINED_STACK_END";
+section6.output_section[4].input_section.create(1);
+section6.output_section[4].input_section[0].$name = ". = . + __UNDEFINED_STACK_SIZE;";
+
+section7.load_memory = "OCRAM";
+section7.$name = "Initialization and Exception Handling";
+section7.output_section.create(3);
+section7.output_section[0].$name = ".ARM.exidx";
+section7.output_section[0].palignment = true;
+section7.output_section[1].$name = ".init_array";
+section7.output_section[1].palignment = true;
+section7.output_section[2].$name = ".fini_array";
+section7.output_section[2].palignment = true;
+
+section8.load_memory = "USER_SHM_MEM";
+section8.type = "NOLOAD";
+section8.$name = "User Shared Memory";
+section8.group = false;
+section8.output_section.create(1);
+section8.output_section[0].$name = ".bss.user_shared_mem";
+section8.output_section[0].alignment = 0;
+
+section9.load_memory = "LOG_SHM_MEM";
+section9.$name = "Log Shared Memory";
+section9.group = false;
+section9.type = "NOLOAD";
+section9.output_section.create(1);
+section9.output_section[0].$name = ".bss.log_shared_mem";
+section9.output_section[0].alignment = 0;
+
+section10.load_memory = "RTOS_NORTOS_IPC_SHM_MEM";
+section10.type = "NOLOAD";
+section10.$name = "IPC Shared Memory";
+section10.group = false;
+section10.output_section.create(1);
+section10.output_section[0].$name = ".bss.ipc_vring_mem";
+section10.output_section[0].alignment = 0;
+
+section11.$name = "CONFIG_SECTION0";
+section11.group = false;
+section11.load_memory = "OCRAM_256K3_RAM";
+section11.output_section.create(1);
+section11.output_section[0].$name = ".PruI2s1RxPingPongBuf";
+section11.output_section[0].alignment = 0;
+
+section12.$name = "CONFIG_SECTION1";
+section12.group = false;
+section12.load_memory = "OCRAM_256K4_RAM";
+section12.output_section.create(1);
+section12.output_section[0].$name = ".TxBuf";
+section12.output_section[0].fill = 2863329520;
+section12.output_section[0].alignment = 0;
+
+section13.$name = "CONFIG_SECTION2";
+section13.group = false;
+section13.load_memory = "OCRAM_256K4_RAM";
+section13.output_section.create(1);
+section13.output_section[0].fill = 1431655765;
+section13.output_section[0].$name = ".RxBuf";
+section13.output_section[0].macro_name = "RXBUF_SECTION";
+section13.output_section[0].alignment = 0;
+
+/**
+ * Pinmux solution for unlocked pins/peripherals. This ensures that minor changes to the automatic solver in a future
+ * version of the tool will not impact the pinmux you originally saw. These lines can be completely deleted in order to
+ * re-solve from scratch.
+ */
+i2c1.I2C.SDA.$suggestSolution = "UART0_CTSn";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.$suggestSolution = "ICSSM";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO5.$suggestSolution = "PR0_PRU0_GPIO5";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO6.$suggestSolution = "PR0_PRU0_GPIO6";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO4.$suggestSolution = "PR0_PRU0_GPIO4";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO0.$suggestSolution = "PR0_PRU0_GPIO0";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO1.$suggestSolution = "PR0_PRU0_GPIO1";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO2.$suggestSolution = "PR0_PRU0_GPIO2";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU0_GPIO3.$suggestSolution = "PR0_PRU0_GPIO3";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO5.$suggestSolution = "PR0_PRU1_GPIO5";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO6.$suggestSolution = "PR0_PRU1_GPIO6";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO4.$suggestSolution = "PR0_PRU1_GPIO4";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO0.$suggestSolution = "PR0_PRU1_GPIO0";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO1.$suggestSolution = "PR0_PRU1_GPIO1";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO2.$suggestSolution = "PR0_PRU1_GPIO2";
+pruicss1.AdditionalICSSSettings[0].PruGPIO[0].ICSSM.PR0_PRU1_GPIO3.$suggestSolution = "PR0_PRU1_GPIO3";
diff --git a/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/main.c b/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/main.c
new file mode 100644
index 000000000..c0fa52de9
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/main.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018-2022 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+#include
+#include "ti_drivers_config.h"
+#include "ti_board_config.h"
+#include "FreeRTOS.h"
+#include "task.h"
+
+#define MAIN_TASK_PRI (configMAX_PRIORITIES-1)
+
+#define MAIN_TASK_SIZE (16384U/sizeof(configSTACK_DEPTH_TYPE))
+StackType_t gMainTaskStack[MAIN_TASK_SIZE] __attribute__((aligned(32)));
+
+StaticTask_t gMainTaskObj;
+TaskHandle_t gMainTask;
+
+void pru_i2s_diagnostic_main(void *args);
+
+void freertos_main(void *args)
+{
+ pru_i2s_diagnostic_main(NULL);
+
+ vTaskDelete(NULL);
+}
+
+
+int main(void)
+{
+ /* init SOC specific modules */
+ System_init();
+ Board_init();
+
+ /* This task is created at highest priority, it should create more tasks and then delete itself */
+ gMainTask = xTaskCreateStatic( freertos_main, /* Pointer to the function that implements the task. */
+ "freertos_main", /* Text name for the task. This is to facilitate debugging only. */
+ MAIN_TASK_SIZE, /* Stack depth in units of StackType_t typically uint32_t on 32b CPUs */
+ NULL, /* We are not using the task parameter. */
+ MAIN_TASK_PRI, /* task priority, 0 is lowest priority, configMAX_PRIORITIES-1 is highest */
+ gMainTaskStack, /* pointer to stack base */
+ &gMainTaskObj ); /* pointer to statically allocated task object memory */
+ configASSERT(gMainTask != NULL);
+
+ /* Start the scheduler to start the tasks executing. */
+ vTaskStartScheduler();
+
+ /* The following line should never be reached because vTaskStartScheduler()
+ will only return if there was not enough FreeRTOS heap memory available to
+ create the Idle and (if configured) Timer tasks. Heap management, and
+ techniques for trapping heap exhaustion, are described in the book text. */
+ DebugP_assertNoLog(0);
+
+ return 0;
+}
diff --git a/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/example.projectspec b/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/example.projectspec
new file mode 100644
index 000000000..73c1312aa
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/example.projectspec
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/makefile b/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/makefile
new file mode 100644
index 000000000..fb6b5244f
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/makefile
@@ -0,0 +1,389 @@
+#
+# Auto generated makefile
+#
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+include $(MCU_PLUS_SDK_PATH)/devconfig/devconfig.mak
+
+
+CG_TOOL_ROOT=$(CGT_TI_ARM_CLANG_PATH)
+
+CC=$(CG_TOOL_ROOT)/bin/tiarmclang
+LNK=$(CG_TOOL_ROOT)/bin/tiarmclang
+STRIP=$(CG_TOOL_ROOT)/bin/tiarmstrip
+OBJCOPY=$(CG_TOOL_ROOT)/bin/tiarmobjcopy
+COV=$(CG_TOOL_ROOT)/bin/tiarmcov
+PROFDATA=$(CG_TOOL_ROOT)/bin/tiarmprofdata
+COVERAGE_PATH=$(abspath .)
+ifeq ($(OS), Windows_NT)
+ PYTHON=python
+else
+ PYTHON=python3
+endif
+
+PROFILE?=release
+ConfigName:=$(PROFILE)
+
+OUTNAME:=pru_i2s_app.$(PROFILE).out
+
+BOOTIMAGE_PATH=$(abspath .)
+BOOTIMAGE_NAME:=pru_i2s_app.$(PROFILE).appimage
+BOOTIMAGE_NAME_XIP:=pru_i2s_app.$(PROFILE).appimage_xip
+BOOTIMAGE_NAME_SIGNED:=pru_i2s_app.$(PROFILE).appimage.signed
+BOOTIMAGE_NAME_MCELF:=pru_i2s_app.$(PROFILE).mcelf
+BOOTIMAGE_NAME_MCELF_HS:=pru_i2s_app.$(PROFILE).mcelf.hs
+BOOTIMAGE_RPRC_NAME:=pru_i2s_app.$(PROFILE).rprc
+BOOTIMAGE_RPRC_NAME_XIP:=pru_i2s_app.$(PROFILE).rprc_xip
+BOOTIMAGE_RPRC_NAME_TMP:=pru_i2s_app.$(PROFILE).rprc_tmp
+BOOTIMAGE_NAME_HS:=pru_i2s_app.$(PROFILE).appimage.hs
+BOOTIMAGE_NAME_HS_FS:=pru_i2s_app.$(PROFILE).appimage.hs_fs
+TARGETS := $(BOOTIMAGE_NAME)
+
+ifeq ($(DEVICE_TYPE), HS)
+ TARGETS += $(BOOTIMAGE_NAME_HS)
+endif
+
+FILES_common := \
+ pru_i2s_diagnostic.c \
+ pru_i2s_app_config.c \
+ main.c \
+ ti_drivers_config.c \
+ ti_drivers_open_close.c \
+ ti_board_config.c \
+ ti_board_open_close.c \
+ ti_dpl_config.c \
+ ti_pinmux_config.c \
+ ti_power_clock_config.c \
+ ioexp_tca6416.c \
+
+FILES_PATH_common = \
+ .. \
+ ../../.. \
+ ../../../board \
+ generated \
+
+INCLUDES_common := \
+ -I${CG_TOOL_ROOT}/include/c \
+ -I${MCU_PLUS_SDK_PATH}/source \
+ -I${OPEN_PRU_PATH}/source \
+ -I${OPEN_PRU_PATH}/examples/pru_i2s/include \
+ -I${OPEN_PRU_PATH}/examples/pru_i2s/firmware \
+ -I${OPEN_PRU_PATH}/examples/pru_i2s/pru_i2s_app \
+ -I${MCU_PLUS_SDK_PATH}/source/kernel/freertos/FreeRTOS-Kernel/include \
+ -I${MCU_PLUS_SDK_PATH}/source/kernel/freertos/portable/TI_ARM_CLANG/ARM_CR5F \
+ -I${MCU_PLUS_SDK_PATH}/source/kernel/freertos/config/am263x/r5f \
+ -I${MCU_PLUS_SDK_PATH}/source/pru_io/driver \
+ -Igenerated \
+
+DEFINES_common := \
+ -DSOC_AM263X \
+ -DOS_FREERTOS \
+
+CFLAGS_common := \
+ -mcpu=cortex-r5 \
+ -mfloat-abi=hard \
+ -mfpu=vfpv3-d16 \
+ -mthumb \
+ -Wall \
+ -Werror \
+ -g \
+ -Wno-gnu-variable-sized-type-not-at-end \
+ -Wno-unused-function \
+
+CFLAGS_cpp_common := \
+ -Wno-c99-designator \
+ -Wno-extern-c-compat \
+ -Wno-c++11-narrowing \
+ -Wno-reorder-init-list \
+ -Wno-register \
+ -Wno-writable-strings \
+ -Wno-enum-compare \
+ -Wno-reserved-user-defined-literal \
+ -Wno-unused-const-variable \
+ -Wno-vla-cxx-extension \
+ -x c++ \
+
+CFLAGS_debug := \
+ -D_DEBUG_=1 \
+
+CFLAGS_release := \
+ -Os \
+
+LNK_FILES_common = \
+ generated/linker.cmd \
+
+LIBS_PATH_common = \
+ -Wl,-i${MCU_PLUS_SDK_PATH}/source/kernel/freertos/lib \
+ -Wl,-i${MCU_PLUS_SDK_PATH}/source/drivers/lib \
+ -Wl,-i${MCU_PLUS_SDK_PATH}/source/board/lib \
+ -Wl,-i${MCU_PLUS_SDK_PATH}/source/pru_io/lib \
+ -Wl,-i${OPEN_PRU_PATH}/examples/pru_i2s/lib \
+ -Wl,-i${CG_TOOL_ROOT}/lib \
+
+LIBS_common = \
+ -lfreertos.am263x.r5f.ti-arm-clang.${ConfigName}.lib \
+ -ldrivers.am263x.r5f.ti-arm-clang.${ConfigName}.lib \
+ -lboard.am263x.r5f.ti-arm-clang.${ConfigName}.lib \
+ -lpru_i2s.am263x.r5f.ti-arm-clang.${ConfigName}.lib \
+ -llibc.a \
+ -llibsysbm.a \
+
+LFLAGS_common = \
+ -Wl,--diag_suppress=10063 \
+ -Wl,--ram_model \
+ -Wl,--reread_libs \
+
+
+LIBS_NAME = \
+ freertos.am263x.r5f.ti-arm-clang.${ConfigName}.lib \
+ drivers.am263x.r5f.ti-arm-clang.${ConfigName}.lib \
+ board.am263x.r5f.ti-arm-clang.${ConfigName}.lib \
+ pru_i2s.am263x.r5f.ti-arm-clang.${ConfigName}.lib \
+ libc.a \
+ libsysbm.a \
+
+LIBS_PATH_NAME = \
+ ${MCU_PLUS_SDK_PATH}/source/kernel/freertos/lib \
+ ${MCU_PLUS_SDK_PATH}/source/drivers/lib \
+ ${MCU_PLUS_SDK_PATH}/source/board/lib \
+ ${MCU_PLUS_SDK_PATH}/source/pru_io/lib \
+ ${OPEN_PRU_PATH}/examples/pru_i2s/lib \
+ ${CG_TOOL_ROOT}/lib \
+
+FILES := $(FILES_common) $(FILES_$(PROFILE))
+ASMFILES := $(ASMFILES_common) $(ASMFILES_$(PROFILE))
+FILES_PATH := $(FILES_PATH_common) $(FILES_PATH_$(PROFILE))
+CFLAGS := $(CFLAGS_common) $(CFLAGS_$(PROFILE))
+ifeq ($(INSTRUMENTATION_MODE), yes)
+CFLAGS += -fprofile-instr-generate -fcoverage-mapping
+endif
+DEFINES := $(DEFINES_common) $(DEFINES_$(PROFILE))
+INCLUDES := $(INCLUDES_common) $(INCLUDE_$(PROFILE))
+LIBS := $(LIBS_common) $(LIBS_$(PROFILE))
+LIBS_PATH := $(LIBS_PATH_common) $(LIBS_PATH_$(PROFILE))
+LFLAGS := $(LFLAGS_common) $(LFLAGS_$(PROFILE))
+LNKOPTFLAGS := $(LNKOPTFLAGS_common) $(LNKOPTFLAGS_$(PROFILE))
+LNK_FILES := $(LNK_FILES_common) $(LNK_FILES_$(PROFILE))
+
+OBJDIR := obj/$(PROFILE)/
+OBJS := $(FILES:%.c=%.obj)
+OBJS += $(ASMFILES:%.S=%.obj)
+DEPS := $(FILES:%.c=%.d)
+
+vpath %.obj $(OBJDIR)
+vpath %.c $(FILES_PATH)
+vpath %.S $(FILES_PATH)
+vpath %.lib $(LIBS_PATH_NAME)
+vpath %.a $(LIBS_PATH_NAME)
+
+$(OBJDIR)/%.obj %.obj: %.c
+ @echo Compiling: am263x:r5fss0-0:freertos:ti-arm-clang $(OUTNAME): $<
+ $(CC) -c $(CFLAGS) $(INCLUDES) $(DEFINES) -MMD -o $(OBJDIR)/$@ $<
+
+$(OBJDIR)/%.obj %.obj: %.S
+ @echo Compiling: am263x:r5fss0-0:freertos:ti-arm-clang $(LIBNAME): $<
+ $(CC) -c $(CFLAGS) -o $(OBJDIR)/$@ $<
+
+all: build_lib_if_needed $(TARGETS)
+
+build_lib_if_needed:
+ @echo "Library is built by parent makefile"
+
+SYSCFG_GEN_FILES=generated/ti_drivers_config.c generated/ti_drivers_config.h
+SYSCFG_GEN_FILES+=generated/ti_drivers_open_close.c generated/ti_drivers_open_close.h
+SYSCFG_GEN_FILES+=generated/ti_dpl_config.c generated/ti_dpl_config.h
+SYSCFG_GEN_FILES+=generated/ti_pinmux_config.c generated/ti_power_clock_config.c
+SYSCFG_GEN_FILES+=generated/ti_board_config.c generated/ti_board_config.h
+SYSCFG_GEN_FILES+=generated/ti_board_open_close.c generated/ti_board_open_close.h
+
+SYSTEM_FLAG ?= false
+
+ifeq ($(SYSTEM_FLAG), false)
+ SYSTEM_COMMAND := syscfg $(SYSCFG_GEN_FILES) $(OBJS) $(LNK_FILES) $(LIBS_NAME)
+else
+ SYSTEM_COMMAND := $(OBJS) $(LNK_FILES) $(LIBS_NAME)
+endif
+
+# Library is built by parent makefile (top-level pru_i2s/makefile)
+pru_i2s.am263x.r5f.ti-arm-clang.$(PROFILE).lib:
+ @echo "Building library via parent makefile..."
+ $(MAKE) -C ../../../.. build_lib_am263x
+
+FORCE:
+
+$(OUTNAME): $(SYSTEM_COMMAND)
+ @echo .
+ @echo Linking: am263x:r5fss0-0:freertos:ti-arm-clang $@ ...
+ $(LNK) $(LNKOPTFLAGS) $(LFLAGS) $(LIBS_PATH) -Wl,-m=$(basename $@).map -o $@ $(addprefix $(OBJDIR), $(OBJS)) $(LIBS) $(LNK_FILES)
+ @echo Linking: am263x:r5fss0-0:freertos:ti-arm-clang $@ Done !!!
+ @echo .
+
+clean:
+ @echo Cleaning: am263x:r5fss0-0:freertos:ti-arm-clang $(OUTNAME) ...
+ $(RMDIR) $(OBJDIR)
+ $(RM) $(OUTNAME)
+ $(RM) $(BOOTIMAGE_NAME)
+ $(RM) $(BOOTIMAGE_NAME_XIP)
+ $(RM) $(BOOTIMAGE_NAME_SIGNED)
+ $(RM) $(BOOTIMAGE_RPRC_NAME)
+ $(RM) $(BOOTIMAGE_RPRC_NAME_XIP)
+ $(RM) $(BOOTIMAGE_NAME_MCELF)
+ $(RMDIR) generated/
+
+scrub:
+ @echo Scrubing: am263x:r5fss0-0:freertos:ti-arm-clang pru_i2s_app ...
+ $(RMDIR) obj
+ifeq ($(OS),Windows_NT)
+ $(RM) \*.out
+ $(RM) \*.map
+ $(RM) \*.appimage*
+ $(RM) \*.rprc*
+ $(RM) \*.tiimage*
+ $(RM) \*.bin
+ $(RM) \*.mcelf
+ $(RM) \*.mcelf_xip
+ $(RM) \*.mcelf-enc
+ $(RM) \*.mcelf.hs
+else
+ $(RM) *.out
+ $(RM) *.map
+ $(RM) *.appimage*
+ $(RM) *.rprc*
+ $(RM) *.tiimage*
+ $(RM) *.bin
+ $(RM) *.mcelf
+ $(RM) *.mcelf_xip
+ $(RM) *.mcelf-enc
+ $(RM) *.mcelf.hs
+endif
+ $(RMDIR) generated
+
+$(OBJS): | $(OBJDIR)
+
+$(OBJDIR):
+ $(MKDIR) $@
+
+
+.NOTPARALLEL:
+
+.INTERMEDIATE: syscfg
+$(SYSCFG_GEN_FILES): syscfg
+
+ifeq ($(SYSTEM_FLAG), false)
+syscfg: ../example.syscfg
+ @echo Generating SysConfig files ...
+ $(SYSCFG_NODE) $(SYSCFG_CLI_PATH)/dist/cli.js --product $(SYSCFG_SDKPRODUCT) --product $(SYSCFG_MCU_PLUS_SDK_PRODUCT) --context r5fss0-0 --part AM263x --package ZCZ --output generated/ ../example.syscfg
+endif
+
+syscfg-gui:
+ $(SYSCFG_NWJS) $(SYSCFG_PATH) --product $(SYSCFG_SDKPRODUCT) --product $(SYSCFG_MCU_PLUS_SDK_PRODUCT) --device AM263x_beta --context r5fss0-0 --part AM263x --package ZCZ --output generated/ ../example.syscfg
+
+#
+# Generation of boot image which can be loaded by Secondary Boot Loader (SBL)
+#
+ifeq ($(OS),Windows_NT)
+EXE_EXT=.exe
+endif
+ifeq ($(OS),Windows_NT)
+ BOOTIMAGE_CERT_GEN_CMD=powershell -executionpolicy unrestricted -command $(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/x509CertificateGen.ps1
+else
+ BOOTIMAGE_CERT_GEN_CMD=$(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/x509CertificateGen.sh
+endif
+BOOTIMAGE_TEMP_OUT_FILE=temp_stdout_$(PROFILE).txt
+
+
+BOOTIMAGE_CORE_ID_r5fss0-0 = 0
+BOOTIMAGE_CORE_ID_r5fss0-1 = 1
+BOOTIMAGE_CORE_ID_r5fss1-0 = 2
+BOOTIMAGE_CORE_ID_r5fss1-1 = 3
+SBL_RUN_ADDRESS=0x70002000
+SBL_DEV_ID=55
+
+MULTI_CORE_IMAGE_GEN = $(SYSCFG_NODE) $(MCU_PLUS_SDK_PATH)/tools/boot/multicoreImageGen/multicoreImageGen.js
+OUTRPRC_CMD = $(SYSCFG_NODE) $(MCU_PLUS_SDK_PATH)/tools/boot/out2rprc/elf2rprc.js
+APP_IMAGE_SIGN_CMD = $(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/mcu_appimage_x509_cert_gen.py
+MCELF_IMAGE_GEN = $(MCU_PLUS_SDK_PATH)/tools/boot/multicore-elf/genimage.py
+
+ifeq ($(OS),Windows_NT)
+ XIPGEN_CMD=$(MCU_PLUS_SDK_PATH)/tools/boot/xipGen/xipGen.exe
+else
+ UNAME_S = $(shell uname -s)
+ ifeq ($(UNAME_S), Darwin)
+ XIPGEN_CMD=$(MCU_PLUS_SDK_PATH)/tools/boot/xipGen/xipGen.out.mac
+ else
+ XIPGEN_CMD=$(MCU_PLUS_SDK_PATH)/tools/boot/xipGen/xipGen.out
+endif
+endif
+
+MULTI_CORE_IMAGE_PARAMS = \
+ $(BOOTIMAGE_RPRC_NAME)@$(BOOTIMAGE_CORE_ID_r5fss0-0) \
+
+MULTI_CORE_IMAGE_PARAMS_XIP = \
+ $(BOOTIMAGE_RPRC_NAME_XIP)@$(BOOTIMAGE_CORE_ID_r5fss0-0) \
+
+$(BOOTIMAGE_NAME): $(OUTNAME)
+ @echo Boot image: am263x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_PATH)/$@ ...
+ifneq ($(OS),Windows_NT)
+ $(CHMOD) a+x $(XIPGEN_CMD)
+endif
+ $(OUTRPRC_CMD) $(OUTNAME) >> $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(COPY) $(BOOTIMAGE_RPRC_NAME) $(BOOTIMAGE_RPRC_NAME_TMP)
+ $(RM) $(BOOTIMAGE_RPRC_NAME)
+ $(XIPGEN_CMD) -i $(BOOTIMAGE_RPRC_NAME_TMP) -o $(BOOTIMAGE_RPRC_NAME) -x $(BOOTIMAGE_RPRC_NAME_XIP) --flash-start-addr 0x60000000 -v > $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(MULTI_CORE_IMAGE_GEN) --devID $(SBL_DEV_ID) --out $(BOOTIMAGE_NAME) $(MULTI_CORE_IMAGE_PARAMS) >> $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(MULTI_CORE_IMAGE_GEN) --devID $(SBL_DEV_ID) --out $(BOOTIMAGE_NAME_XIP) $(MULTI_CORE_IMAGE_PARAMS_XIP) >> $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(RM) $(BOOTIMAGE_RPRC_NAME_TMP)
+ $(RM) $(BOOTIMAGE_TEMP_OUT_FILE)
+ @echo Boot image: am263x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_PATH)/$@ Done !!!
+ @echo Boot MulticoreELF image: $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_MCELF) ...
+ $(PYTHON) $(MCELF_IMAGE_GEN) --core-img=$(BOOTIMAGE_CORE_ID_r5fss0-0):$(OUTNAME) --output=$(BOOTIMAGE_NAME_MCELF) --merge-segments=$(MCELF_MERGE_SEGMENTS_FLAG) --tolerance-limit=$(MCELF_MERGE_SEGMENTS_TOLERANCE_LIMIT) --ignore-context=$(MCELF_IGNORE_CONTEXT_FLAG) --xip=$(MCELF_XIP_RANGE) --xlat=$(MCELF_ADDR_TRANSLATION_PATH) --max-segment-size=$(MCELF_MAX_SEGMENT_SIZE)
+ @echo Boot MulticoreELF ELF image: $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_MCELF) Done !!!
+ @echo .
+
+$(BOOTIMAGE_NAME_HS): $(BOOTIMAGE_NAME)
+ifeq ($(DEVICE_TYPE), HS)
+# Sign the appimage using appimage signing script
+ifeq ($(ENC_ENABLED),no)
+ifeq ($(RSASSAPSS_ENABLED),no)
+ @echo Boot image signing: Encryption is disabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_HS)
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_MCELF_HS)
+else
+ @echo Boot image signing: Encryption is disabled. RSASSAPSS is enabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_HS) --rsassa_pss
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_MCELF_HS) --rsassa_pss
+endif
+else
+ifeq ($(RSASSAPSS_ENABLED),no)
+ @echo Boot image signing: Encryption is enabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_HS)
+ $(RM) $(BOOTIMAGE_NAME)-enc
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_MCELF_HS)
+ $(RM) $(BOOTIMAGE_NAME_MCELF)-enc
+else
+ @echo Boot image signing: Encryption is enabled. RSASSAPSS is enabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_HS) --rsassa_pss
+ $(RM) $(BOOTIMAGE_NAME)-enc
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_MCELF_HS) --rsassa_pss
+ $(RM) $(BOOTIMAGE_NAME_MCELF)-enc
+endif
+endif
+ @echo Boot image: am263x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_HS) Done !!!
+ @echo Boot image: am263x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_MCELF_HS) Done !!!
+ @echo .
+endif
+
+
+
+.PHONY: coverage
+coverage:
+ @echo Creating Coverage Report for pru_i2s_app.$(PROFILE) ...
+ $(MKDIR) coverage
+ $(PROFDATA) merge -sparse -obj-file=$(OUTNAME) $(OUTNAME).cnt -o pru_i2s_app.$(PROFILE).profdata
+ $(COV) show --format=html --show-expansions --show-instantiations --show-branches=count --object=$(OUTNAME) -instr-profile=pru_i2s_app.$(PROFILE).profdata --output-dir=$(COVERAGE_PATH)/coverage --ignore-filename-regex=build_jenkins
+ $(COV) export --format=text --object=$(OUTNAME) --instr-profile=pru_i2s_app.$(PROFILE).profdata > coverage/pru_i2s_app.$(PROFILE).profdata.json
+ node $(MCU_PLUS_SDK_PATH)/tools/smart_placement/clang_coverage_analyse.js --input=coverage/pru_i2s_app.$(PROFILE).profdata.json --output-json=coverage/pru_i2s_app.$(PROFILE).analysis.json --output=../pru_i2s_app.annotations.$(PROFILE).S --top-function-count=500
+ @echo Coverage Report Generated at $(COVERAGE_PATH)/coverage folder !!!
+
+-include $(addprefix $(OBJDIR)/, $(DEPS))
diff --git a/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/makefile_ccs_bootimage_gen b/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/makefile_ccs_bootimage_gen
new file mode 100644
index 000000000..4af88cd03
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/makefile_ccs_bootimage_gen
@@ -0,0 +1,141 @@
+#
+# Auto generated makefile
+#
+
+# Below variables need to be defined outside this file or via command line
+# - OPEN_PRU_PATH
+# - MCU_PLUS_SDK_PATH
+# - PROFILE
+# - CG_TOOL_ROOT
+# - OUTNAME
+# - CCS_INSTALL_DIR
+# - CCS_IDE_MODE
+
+CCS_PATH=$(CCS_INSTALL_DIR)
+include $(OPEN_PRU_PATH)/imports.mak
+include $(MCU_PLUS_SDK_PATH)/devconfig/devconfig.mak
+
+STRIP=$(CG_TOOL_ROOT)/bin/tiarmstrip
+OBJCOPY=$(CG_TOOL_ROOT)/bin/tiarmobjcopy
+ifeq ($(OS), Windows_NT)
+ PYTHON=python
+else
+ PYTHON=python3
+endif
+
+OUTFILE=$(PROFILE)/$(OUTNAME).out
+BOOTIMAGE_PATH=$(abspath ${PROFILE})
+BOOTIMAGE_NAME:=$(BOOTIMAGE_PATH)/$(OUTNAME).appimage
+BOOTIMAGE_NAME_XIP:=$(BOOTIMAGE_PATH)/$(OUTNAME).appimage_xip
+BOOTIMAGE_NAME_SIGNED:=$(BOOTIMAGE_PATH)/$(OUTNAME).appimage.signed
+BOOTIMAGE_RPRC_NAME:=$(BOOTIMAGE_PATH)/$(OUTNAME).rprc
+BOOTIMAGE_RPRC_NAME_XIP:=$(BOOTIMAGE_PATH)/$(OUTNAME).rprc_xip
+BOOTIMAGE_RPRC_NAME_TMP:=$(BOOTIMAGE_PATH)/$(OUTNAME).rprc_tmp
+BOOTIMAGE_NAME_MCELF:=$(BOOTIMAGE_PATH)/$(OUTNAME).mcelf
+BOOTIMAGE_NAME_MCELF_HS:=$(BOOTIMAGE_PATH)/$(OUTNAME).mcelf.hs
+BOOTIMAGE_NAME_HS:=$(BOOTIMAGE_PATH)/pru_i2s_app.$(PROFILE).appimage.hs
+BOOTIMAGE_NAME_HS_FS:=$(BOOTIMAGE_PATH)/pru_i2s_app.$(PROFILE).appimage.hs_fs
+TARGETS := $(BOOTIMAGE_NAME)
+TARGETS += $(BOOTIMAGE_NAME_MCELF)
+TARGETS += $(BOOTIMAGE_NAME_MCELF_HS)
+ifeq ($(DEVICE_TYPE), HS)
+ TARGETS += $(BOOTIMAGE_NAME_HS)
+endif
+
+#
+# Generation of boot image which can be loaded by Secondary Boot Loader (SBL)
+#
+ifeq ($(OS),Windows_NT)
+EXE_EXT=.exe
+endif
+ifeq ($(OS),Windows_NT)
+ BOOTIMAGE_CERT_GEN_CMD=powershell -executionpolicy unrestricted -command $(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/x509CertificateGen.ps1
+else
+ BOOTIMAGE_CERT_GEN_CMD=$(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/x509CertificateGen.sh
+endif
+BOOTIMAGE_TEMP_OUT_FILE=$(PROFILE)/temp_stdout_$(PROFILE).txt
+
+BOOTIMAGE_CORE_ID_r5fss0-0 = 0
+BOOTIMAGE_CORE_ID_r5fss0-1 = 1
+BOOTIMAGE_CORE_ID_r5fss1-0 = 2
+BOOTIMAGE_CORE_ID_r5fss1-1 = 3
+SBL_RUN_ADDRESS=0x70002000
+SBL_DEV_ID=55
+
+MULTI_CORE_IMAGE_GEN = $(CCS_NODE) $(MCU_PLUS_SDK_PATH)/tools/boot/multicoreImageGen/multicoreImageGen.js
+OUTRPRC_CMD = $(CCS_NODE) $(MCU_PLUS_SDK_PATH)/tools/boot/out2rprc/elf2rprc.js
+APP_IMAGE_SIGN_CMD = $(MCU_PLUS_SDK_PATH)/source/security/security_common/tools/boot/signing/mcu_appimage_x509_cert_gen.py
+MCELF_IMAGE_GEN = $(MCU_PLUS_SDK_PATH)/tools/boot/multicore-elf/genimage.py
+
+ifeq ($(OS),Windows_NT)
+ XIPGEN_CMD=$(MCU_PLUS_SDK_PATH)/tools/boot/xipGen/xipGen.exe
+else
+ UNAME_S = $(shell uname -s)
+ ifeq ($(UNAME_S), Darwin)
+ XIPGEN_CMD=$(MCU_PLUS_SDK_PATH)/tools/boot/xipGen/xipGen.out.mac
+ else
+ XIPGEN_CMD=$(MCU_PLUS_SDK_PATH)/tools/boot/xipGen/xipGen.out
+endif
+endif
+
+MULTI_CORE_IMAGE_PARAMS = \
+ $(BOOTIMAGE_RPRC_NAME)@$(BOOTIMAGE_CORE_ID_r5fss0-0) \
+
+MULTI_CORE_IMAGE_PARAMS_XIP = \
+ $(BOOTIMAGE_RPRC_NAME_XIP)@$(BOOTIMAGE_CORE_ID_r5fss0-0) \
+
+all:
+ifeq ($(CCS_IDE_MODE),cloud)
+# No post build steps
+else
+ @echo Boot image: am263x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_NAME) ...
+ $(OUTRPRC_CMD) $(OUTFILE) >> $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(COPY) $(OUTNAME).rprc $(BOOTIMAGE_RPRC_NAME)
+ $(COPY) $(BOOTIMAGE_RPRC_NAME) $(BOOTIMAGE_RPRC_NAME_TMP)
+ $(RM) $(BOOTIMAGE_RPRC_NAME)
+ $(XIPGEN_CMD) -i $(BOOTIMAGE_RPRC_NAME_TMP) -o $(BOOTIMAGE_RPRC_NAME) -x $(BOOTIMAGE_RPRC_NAME_XIP) --flash-start-addr 0x60000000 -v > $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(MULTI_CORE_IMAGE_GEN) --devID $(SBL_DEV_ID) --out $(BOOTIMAGE_NAME) $(MULTI_CORE_IMAGE_PARAMS) >> $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(MULTI_CORE_IMAGE_GEN) --devID $(SBL_DEV_ID) --out $(BOOTIMAGE_NAME_XIP) $(MULTI_CORE_IMAGE_PARAMS_XIP) >> $(BOOTIMAGE_TEMP_OUT_FILE)
+ $(RM) $(BOOTIMAGE_RPRC_NAME_TMP)
+
+ @echo Boot multi-core ELF image: am263x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_NAME_MCELF) ...
+
+ $(PYTHON) $(MCELF_IMAGE_GEN) --core-img=$(BOOTIMAGE_CORE_ID_r5fss0-0):$(OUTFILE) --output=$(BOOTIMAGE_NAME_MCELF) --merge-segments=$(MCELF_MERGE_SEGMENTS_FLAG) --tolerance-limit=$(MCELF_MERGE_SEGMENTS_TOLERANCE_LIMIT) --ignore-context=$(MCELF_IGNORE_CONTEXT_FLAG) --xip=$(MCELF_XIP_RANGE) --xlat=$(MCELF_ADDR_TRANSLATION_PATH) --max_segment_size=$(MCELF_MAX_SEGMENT_SIZE)
+
+ @echo Boot multi-core ELF image: $(BOOTIMAGE_NAME_MCELF) Done !!!
+ @echo .
+
+ @echo Boot image: am263x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_NAME) Done !!!
+ @echo .
+ifeq ($(DEVICE_TYPE), HS)
+# Sign the appimage using appimage signing script
+ifeq ($(ENC_ENABLED),no)
+ifeq ($(RSASSAPSS_ENABLED),no)
+ @echo Boot image signing: Encryption is disabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_HS)
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_MCELF_HS)
+else
+ @echo Boot image signing: Encryption is disabled. RSASSA-PSS is enabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_HS) --rsassa_pss
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_MCELF_HS) --rsassa_pss
+endif
+else
+ifeq ($(RSASSAPSS_ENABLED),no)
+ @echo Boot image signing: Encryption is enabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_HS)
+ $(RM) $(BOOTIMAGE_NAME)-enc
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --output $(BOOTIMAGE_NAME_MCELF_HS)
+ $(RM) $(BOOTIMAGE_NAME_MCELF)-enc
+else
+ @echo Boot image signing: Encryption is enabled. RSASSA-PSS is enabled.
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_HS) --rsassa_pss
+ $(RM) $(BOOTIMAGE_NAME)-enc
+ $(PYTHON) $(APP_IMAGE_SIGN_CMD) --bin $(BOOTIMAGE_NAME_MCELF) --key $(APP_SIGNING_KEY) --enc y --enckey $(APP_ENCRYPTION_KEY) --kd-salt $(KD_SALT) --sign_key_id $(APP_SIGNING_KEY_KEYRING_ID) --enc_key_id $(APP_ENCRYPTION_KEY_KEYRING_ID) --hash_algo $(APP_SIGNING_HASH_ALGO) --pss_saltlen $(APP_SIGNING_SALT_LENGTH) --output $(BOOTIMAGE_NAME_MCELF_HS) --rsassa_pss
+ $(RM) $(BOOTIMAGE_NAME_MCELF)-enc
+endif
+endif
+ @echo Boot image: am263x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_HS) Done !!!
+ @echo Boot image: am263x:r5fss0-0:freertos:ti-arm-clang $(BOOTIMAGE_PATH)/$(BOOTIMAGE_NAME_MCELF_HS) Done !!!
+ @echo .
+endif
+endif
diff --git a/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/makefile_projectspec b/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/makefile_projectspec
new file mode 100644
index 000000000..1392f9587
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/makefile_projectspec
@@ -0,0 +1,20 @@
+#
+# Auto generated makefile
+#
+
+export OPEN_PRU_PATH?=$(abspath ../../../../../..)
+include $(OPEN_PRU_PATH)/imports.mak
+
+PROFILE?=Release
+
+PROJECT_NAME=pru_i2s_app_am263x-cc_r5fss0-0_freertos_ti-arm-clang
+
+all:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE)
+
+clean:
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectBuild -ccs.projects $(PROJECT_NAME) -ccs.configuration $(PROFILE) -ccs.clean
+
+export:
+ $(MKDIR) $(OPEN_PRU_PATH)/ccs_projects
+ $(CCS_ECLIPSE) -noSplash -data $(OPEN_PRU_PATH)/ccs_projects -application com.ti.ccstudio.apps.projectCreate -ccs.projectSpec example.projectspec -ccs.overwrite full
diff --git a/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/syscfg_c.rov.xs b/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/syscfg_c.rov.xs
new file mode 100644
index 000000000..472ab3849
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/am263x-cc/r5fss0-0_freertos/ti-arm-clang/syscfg_c.rov.xs
@@ -0,0 +1,8 @@
+/*
+ * ======== syscfg_c.rov.xs ========
+ * This file contains the information needed by the Runtime Object
+ * View (ROV) tool.
+ */
+var crovFiles = [
+ "kernel/freertos/rov/FreeRTOS.rov.js",
+];
diff --git a/examples/pru_i2s/pru_i2s_app/board/ioexp_tca6416.c b/examples/pru_i2s/pru_i2s_app/board/ioexp_tca6416.c
new file mode 100644
index 000000000..0eb3b6866
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/board/ioexp_tca6416.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* ========================================================================== */
+/* Include Files */
+/* ========================================================================== */
+
+#include "ioexp_tca6416.h"
+
+extern I2C_Handle gI2cHandle[];
+
+/* ========================================================================== */
+/* Macros & Typedefs */
+/* ========================================================================== */
+
+#define TCA6416_REG_INPUT_PORT_0 (0x00U)
+#define TCA6416_REG_INPUT_PORT_1 (0x01U)
+#define TCA6416_REG_OUTPUT_PORT_0 (0x02U)
+#define TCA6416_REG_OUTPUT_PORT_1 (0x03U)
+#define TCA6416_REG_POL_INV_PORT_0 (0x04U)
+#define TCA6416_REG_POL_INV_PORT_1 (0x05U)
+#define TCA6416_REG_CONFIG_PORT_0 (0x06U)
+#define TCA6416_REG_CONFIG_PORT_1 (0x07U)
+
+/* ========================================================================== */
+/* Structure Declarations */
+/* ========================================================================== */
+
+/* None */
+
+/* ========================================================================== */
+/* Function Declarations */
+/* ========================================================================== */
+
+/* None */
+
+/* ========================================================================== */
+/* Global Variables */
+/* ========================================================================== */
+
+/* None */
+
+/* ========================================================================== */
+/* Function Definitions */
+/* ========================================================================== */
+
+int32_t TCA6416_open(TCA6416_Config *config, const TCA6416_Params *params)
+{
+ int32_t status = SystemP_SUCCESS;
+
+ if((NULL == config) || (NULL == params))
+ {
+ status = SystemP_FAILURE;
+ }
+ else
+ {
+ config->params.i2cInstance = params->i2cInstance;
+ config->params.i2cAddress = params->i2cAddress;
+ config->lock = NULL;
+ // config->i2cHandle = I2C_getHandle(config->params.i2cInstance);
+ config->i2cHandle = gI2cHandle[config->params.i2cInstance];
+ if(NULL == config->i2cHandle)
+ {
+ status = SystemP_FAILURE;
+ }
+ }
+
+ if(status == SystemP_SUCCESS)
+ {
+ SemaphoreP_constructMutex(&config->lockObj);
+ config->lock = &config->lockObj;
+ TCA6416_getAttrs(config, &config->attrs);
+ }
+
+ return (status);
+}
+
+void TCA6416_close(TCA6416_Config *config)
+{
+ if(NULL != config)
+ {
+ /* I2C Driver will be closed outside flash */
+ config->i2cHandle = NULL;
+ if(NULL != config->lock)
+ {
+ SemaphoreP_destruct(&config->lockObj);
+ config->lock = NULL;
+ }
+ }
+
+ return;
+}
+
+int32_t TCA6416_config(TCA6416_Config *config, uint32_t ioIndex, uint32_t mode)
+{
+ int32_t status = SystemP_SUCCESS;
+ I2C_Transaction i2cTransaction;
+ uint32_t port, portPin, i2cAddress;
+ uint8_t buffer[2U] = {0};
+
+ if(NULL == config)
+ {
+ status = SystemP_FAILURE;
+ }
+ else
+ {
+ /* Validate input IO number */
+ if(ioIndex >= config->attrs.numIo)
+ {
+ status = SystemP_FAILURE;
+ }
+ }
+
+ if(status == SystemP_SUCCESS)
+ {
+ /* Each port contains 8 IOs */
+ port = ioIndex >> 3U; /* /8 gives port */
+ portPin = ioIndex & 0x07U; /* %8 gives pin within port */
+ i2cAddress = config->params.i2cAddress;
+
+ SemaphoreP_pend(&config->lockObj, SystemP_WAIT_FOREVER);
+
+ /* Set config register address - needed for next read */
+ I2C_Transaction_init(&i2cTransaction);
+ buffer[0] = TCA6416_REG_CONFIG_PORT_0 + port;
+ i2cTransaction.writeBuf = buffer;
+ i2cTransaction.writeCount = 1U;
+ i2cTransaction.targetAddress = i2cAddress;
+ if (I2C_transfer(config->i2cHandle, &i2cTransaction) != SystemP_SUCCESS)
+ {
+ status = SystemP_FAILURE;
+ }
+
+ /* Read config register value */
+ I2C_Transaction_init(&i2cTransaction);
+ i2cTransaction.readBuf = buffer;
+ i2cTransaction.readCount = 1;
+ i2cTransaction.targetAddress = i2cAddress;
+ if (I2C_transfer(config->i2cHandle, &i2cTransaction) != SystemP_SUCCESS)
+ {
+ status = SystemP_FAILURE ;
+ }
+ /* Set output or input mode to particular IO pin - read/modify/write */
+ I2C_Transaction_init(&i2cTransaction);
+ if(TCA6416_MODE_INPUT == mode)
+ {
+ buffer[1] = buffer[0] | (0x01 << portPin);
+ }
+ else
+ {
+ buffer[1] = buffer[0] & ~(0x01 << portPin);
+ }
+ buffer[0] = TCA6416_REG_CONFIG_PORT_0 + port;
+ i2cTransaction.writeBuf = buffer;
+ i2cTransaction.writeCount = 2;
+ i2cTransaction.targetAddress = i2cAddress;
+ if (I2C_transfer(config->i2cHandle, &i2cTransaction) != SystemP_SUCCESS)
+ {
+ status = SystemP_FAILURE ;
+ }
+ SemaphoreP_post(&config->lockObj);
+ }
+
+ return (status);
+}
+
+int32_t TCA6416_setOutput(TCA6416_Config *config, uint32_t ioIndex, uint32_t state)
+{
+ int32_t status = SystemP_SUCCESS;
+ I2C_Transaction i2cTransaction;
+ uint32_t port, portPin, i2cAddress;
+ uint8_t buffer[2U] = {0};
+
+ if(NULL == config)
+ {
+ status = SystemP_FAILURE;
+ }
+ else
+ {
+ /* Validate input IO number */
+ if(ioIndex >= config->attrs.numIo)
+ {
+ status = SystemP_FAILURE;
+ }
+ }
+
+ if(status == SystemP_SUCCESS)
+ {
+ /* Each port contains 8 IOs */
+ port = ioIndex >> 3U; /* /8 gives port */
+ portPin = ioIndex & 0x07U; /* %8 gives pin within port */
+ i2cAddress = config->params.i2cAddress;
+
+ SemaphoreP_pend(&config->lockObj, SystemP_WAIT_FOREVER);
+
+ /* Set output port register address - needed for next read */
+ I2C_Transaction_init(&i2cTransaction);
+ buffer[0] = TCA6416_REG_OUTPUT_PORT_0 + port;
+ i2cTransaction.writeBuf = buffer;
+ i2cTransaction.writeCount = 1U;
+ i2cTransaction.targetAddress = i2cAddress;
+ status += I2C_transfer(config->i2cHandle, &i2cTransaction);
+
+ /* Read config register value */
+ I2C_Transaction_init(&i2cTransaction);
+ i2cTransaction.readBuf = buffer;
+ i2cTransaction.readCount = 1;
+ i2cTransaction.targetAddress = i2cAddress;
+ status += I2C_transfer(config->i2cHandle, &i2cTransaction);
+
+ /* Set output or input mode to particular IO pin - read/modify/write */
+ I2C_Transaction_init(&i2cTransaction);
+ if(TCA6416_OUT_STATE_HIGH == state)
+ {
+ buffer[1] = buffer[0] | (0x01 << portPin);
+ }
+ else
+ {
+ buffer[1] = buffer[0] & ~(0x01 << portPin);
+ }
+ buffer[0] = TCA6416_REG_OUTPUT_PORT_0 + port;
+ i2cTransaction.writeBuf = buffer;
+ i2cTransaction.writeCount = 2;
+ i2cTransaction.targetAddress = i2cAddress;
+ status += I2C_transfer(config->i2cHandle, &i2cTransaction);
+
+ SemaphoreP_post(&config->lockObj);
+ }
+
+ return (status);
+}
+
+void TCA6416_getAttrs(TCA6416_Config *config, TCA6416_Attrs *attrs)
+{
+ if(NULL != attrs)
+ {
+ attrs->numIo = 16U;
+ }
+
+ return;
+}
+
+void TCA6416_Params_init(TCA6416_Params *params)
+{
+ if(NULL != params)
+ {
+ params->i2cInstance = 2U;
+ params->i2cAddress = 0x20U;
+ }
+
+ return;
+}
diff --git a/examples/pru_i2s/pru_i2s_app/board/ioexp_tca6416.h b/examples/pru_i2s/pru_i2s_app/board/ioexp_tca6416.h
new file mode 100644
index 000000000..fbb123f69
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/board/ioexp_tca6416.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \defgroup BOARD_IO_EXPANDER_TCA6416_MODULE APIs for TCA6416 IO Expander driver
+ * \ingroup BOARD_MODULE
+ *
+ * This module contains APIs to program and use I2C based TCA6416 IO Expander
+ * module on the board.
+ *
+ * @{
+ */
+
+#ifndef IO_EXP_TCA6416_H_
+#define IO_EXP_TCA6416_H_
+
+/* ========================================================================== */
+/* Include Files */
+/* ========================================================================== */
+
+#include
+#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ========================================================================== */
+/* Macros & Typedefs */
+/* ========================================================================== */
+
+/**
+ * \anchor TCA6416_Mode
+ * \name IO pin mode - Input or Output
+ * @{
+ */
+/** \brief Configure IO pin as input */
+#define TCA6416_MODE_INPUT (0U)
+/** \brief Configure IO pin as output */
+#define TCA6416_MODE_OUTPUT (1U)
+/** @} */
+
+/**
+ * \anchor TCA6416_OutState
+ * \name IO pin output state - HIGH or LOW
+ * @{
+ */
+/** \brief Configure IO pin output as LOW */
+#define TCA6416_OUT_STATE_LOW (0U)
+/** \brief Configure IO pin output as HIGH */
+#define TCA6416_OUT_STATE_HIGH (1U)
+/** @} */
+
+/* ========================================================================== */
+/* Structure Declarations */
+/* ========================================================================== */
+
+/**
+ * \brief Parameters passed during TCA6416_open()
+ */
+typedef struct TCA6416_Params_s
+{
+ uint32_t i2cInstance;
+ /**< Underlying peripheral driver instance that is used by the
+ * IO Expander driver incase of I2C controlled IO Expander */
+ uint32_t i2cAddress;
+ /**< I2C address for IO expander */
+} TCA6416_Params;
+
+/**
+ * \brief IO Expander device attributes.
+ */
+typedef struct TCA6416_Attrs_s
+{
+ uint32_t numIo;
+ /**< Number of IO supported by device */
+} TCA6416_Attrs;
+
+/**
+ * \brief IO Expander driver configuration. This is the driver object used to
+ * store state variables
+ */
+typedef struct TCA6416_Config_s
+{
+ TCA6416_Params params;
+ /**< Parameters */
+ TCA6416_Attrs attrs;
+ /**< Attributes */
+ I2C_Handle i2cHandle;
+ /**< I2C driver handle */
+ void *lock;
+ /**< Mutex to protect IO expander access. */
+ SemaphoreP_Object lockObj;
+ /**< Mutex object. */
+} TCA6416_Config;
+
+/* ========================================================================== */
+/* Function Declarations */
+/* ========================================================================== */
+
+/**
+ * \brief Open TCA6416 driver
+ *
+ * Make sure the I2C driver is opened before calling this API.
+ *
+ * \param config [IN] Driver object. Caller need to allocate memory for this.
+ * \param params [IN] Open parameters
+ *
+ * \return SystemP_SUCCESS on success, else failure
+ */
+int32_t TCA6416_open(TCA6416_Config *config, const TCA6416_Params *params);
+
+/**
+ * \brief Close TCA6416 driver
+ *
+ * \param config [IN] TCA6416 driver config from \ref TCA6416_open
+ */
+void TCA6416_close(TCA6416_Config *config);
+
+/**
+ * \brief API to set a IO pin of TCA6416 as input or output
+ *
+ * \param config [IN] TCA6416 driver config from \ref TCA6416_open
+ * \param ioIndex [IN] Index to the TCA6416 IO which needs to be set/reset.
+ * \param mode [IN] Refer \ref TCA6416_Mode
+ *
+ * \return SystemP_SUCCESS on success, else failure
+ */
+int32_t TCA6416_config(TCA6416_Config *config, uint32_t ioIndex, uint32_t mode);
+
+/**
+ * \brief API to set a IO pin of TCA6416 to either HIGH or LOW
+ *
+ * \param config [IN] TCA6416 driver config from \ref TCA6416_open
+ * \param ioIndex [IN] Index to the TCA6416 IO which needs to be set/reset.
+ * \param state [IN] Refer \ref TCA6416_OutState
+ *
+ * \return SystemP_SUCCESS on success, else failure
+ */
+int32_t TCA6416_setOutput(TCA6416_Config *config, uint32_t ioIndex, uint32_t state);
+
+/**
+ * \brief Returns TCA6416 attributes
+ *
+ * \param config [IN] TCA6416 driver config from \ref TCA6416_open
+ * \param attrs [IN/OUT] Structure where the attribute is returned
+ *
+ */
+void TCA6416_getAttrs(TCA6416_Config *config, TCA6416_Attrs *attrs);
+
+/**
+ * \brief Set default parameters in the \ref TCA6416_Params structure
+ *
+ * Call this API to set defaults and then override the fields as needed
+ * before calling \ref TCA6416_open.
+ *
+ * \param params [OUT] Initialized parameters
+ */
+void TCA6416_Params_init(TCA6416_Params *params);
+
+/* ========================================================================== */
+/* Static Function Definitions */
+/* ========================================================================== */
+
+/* None */
+
+/* ========================================================================== */
+/* Internal/Private Structure Declarations */
+/* ========================================================================== */
+
+/* None */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef TCA6416_H_ */
+
+/** @} */
diff --git a/examples/pru_i2s/pru_i2s_app/data.h b/examples/pru_i2s/pru_i2s_app/data.h
new file mode 100644
index 000000000..9e4cc8397
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/data.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024-2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef DATA_H_
+#define DATA_H_
+/* Constants for system configuration and behavior */
+#define SEMAPHORE_TIMEOUT_MS 5000 /* 5 second timeout for semaphore operations */
+#define ERROR_COUNT_THRESHOLD 10 /* Threshold for error counts before taking action */
+#define ERROR_LOG_INTERVAL 10 /* Log errors on first occurrence and every Nth after */
+
+/* Constants for buffer management */
+#define PING_PONG_BUFFER_COUNT 2 /* Number of ping-pong buffers (always 2) */
+#define RX_BUFFER_STORAGE_FACTOR 60 /* Store data equivalent to 60 ping-pong buffers */
+#define BYTES_PER_32BIT_WORD 4 /* Number of bytes in a 32-bit word */
+
+/* IO Expander index values */
+#define IOEXP_INDEX_P20 0x10 /* P20 = LED 3 bits, pin, 2 bits port */
+#define IOEXP_INDEX_P02 0x02 /* P02 index */
+#define IOEXP_INDEX_P03 0x03 /* P03 index */
+
+/* Audio processing constants */
+#ifdef _DBG_PRUI2S_RX_TO_TX_LB
+#define GAIN_MINUS_3DB 0.7071f /* Left channel gain (-3 dB attenuation) */
+#define GAIN_MINUS_6DB 0.5f /* Right channel gain (-6 dB attenuation) */
+#define CHANNEL_MIX_DIVISOR 2 /* Divisor for channel mixing (simple average) */
+#endif
+
+/* Error bit position macro */
+#define ERROR_BIT_POSITION(bit) (1 << (bit))
+#define BYTES_PER_32BIT_WORD 4
+/* Rx buffers -- interleaved format */
+/* Redefine with more descriptive constants */
+#define RX_BUF_SZ (PRUI2S1_RX_PING_PONG_BUF_SZ/PING_PONG_BUFFER_COUNT*RX_BUFFER_STORAGE_FACTOR) /* 60 PP buffers */
+#define RX_BUF_SZ_32B (RX_BUF_SZ/BYTES_PER_32BIT_WORD)
+
+/* Tx ping/pong buffer addresses in ICSSG SHMEM (local PRU view, not SoC view) */
+#define PRUI2S0_TX_PING_PONG_BASE_ADDR ( 0x10000 )
+
+/* PRU I2S0 total Tx ping+pong buffer size in bytes
+ 32 sample/channel * (4 byte/sample) * (2 channel/I2S) * (3 I2S/PP buffer) = 768 byte/PP buffer
+ 768 byte/PP buffer * 2 PP buffer = 1536 bytes
+*/
+#define PRUI2S0_TX_PING_PONG_BUF_SZ ( 1536 )
+/* PRU I2S0 total Tx ping+pong buffer size in 32-bit words */
+#define PRUI2S0_TX_PING_PONG_BUF_SZ_32B ( PRUI2S0_TX_PING_PONG_BUF_SZ/4 )
+
+/* PRU I2S1 total Rx ping+pong buffer size in bytes
+ 32 sample/channel * (4 byte/sample) * (2 channel/I2S) * (2 I2S/PP buffer) = 512 byte/PP buffer
+ 512 byte/PP buffer * 2 PP buffer = 1024 bytes
+*/
+#define PRUI2S1_RX_PING_PONG_BUF_SZ ( 1536 )
+/* PRU I2S1 total Rx ping+pong buffer size in 32-bit words */
+#define PRUI2S1_RX_PING_PONG_BUF_SZ_32B ( PRUI2S1_RX_PING_PONG_BUF_SZ/4 )
+
+/* Rx ping/pong buffers */
+__attribute__((section(".PruI2s1RxPingPongBuf"))) int32_t gPruI2s1RxPingPongBuf[PRUI2S1_RX_PING_PONG_BUF_SZ_32B];
+
+/* Tx buffers -- interleaved format */
+#define TX_BUF_SZ ( PRUI2S0_TX_PING_PONG_BUF_SZ/2*60 ) /* 60 PP buffers */
+#define TX_BUF_SZ_32B ( TX_BUF_SZ/4 )
+__attribute__((section(".TxBuf"))) int32_t gPruI2s0TxBuf[TX_BUF_SZ_32B] =
+{0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,
+ 0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0001,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,
+ 0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,
+ 0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,
+ 0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,
+ 0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,
+ 0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,
+ 0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000,0xaaaaffff,0x0000aaaa,0x0000ffff,0xaaaa0000
+ };
+#endif /* DATA_H_ */
diff --git a/examples/pru_i2s/pru_i2s_app/pru_i2s_app_config.c b/examples/pru_i2s/pru_i2s_app/pru_i2s_app_config.c
new file mode 100644
index 000000000..9b32a8490
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/pru_i2s_app_config.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2024-2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file pru_i2s_app_config.c
+ *
+ * \brief PRU I2S Application Configuration
+ *
+ * This file contains the application-specific configuration for PRU I2S.
+ * Modify pru_i2s_app_config.h to configure:
+ * - ICSS instance selection (ICSSM0 or ICSSM1)
+ * - PRU core selection (PRU0 or PRU1)
+ * - I2S/TDM mode selection
+ * - Instance enable flags
+ */
+
+#include "pru_i2s_config.h"
+#include "pru_i2s_drv.h"
+#include "pru_i2s_app_config.h"
+
+/* ========================================================================== */
+/* USER CONFIGURATION */
+/* ========================================================================== */
+
+/**
+ * \brief PRU I2S Configuration Table
+ *
+ * This table defines the configuration for each PRU I2S instance.
+ *
+ * For AM261x LaunchPad:
+ * - Uses ICSSM1 (icssInstId = 1)
+ * - PRU0 for Tx, PRU1 for Rx
+ *
+ * For AM263x Control Card:
+ * - Uses ICSSM0 (icssInstId = 0)
+ * - PRU0 and PRU1 for Tx and Rx
+ *
+ * Modify the values below to match your hardware configuration.
+ */
+static const PRUI2S_UserConfig gPruI2sAppConfig[PRU_I2S_NUM_CONFIG] =
+{
+ /* Configuration 0: First PRU core */
+ PRUI2S_USER_CONFIG_PRU0,
+
+ /* Configuration 1: Second PRU core */
+ PRUI2S_USER_CONFIG_PRU1
+};
+
+/* ========================================================================== */
+/* FUNCTION DEFINITIONS */
+/* ========================================================================== */
+
+/**
+ * \brief Apply PRU I2S application configuration
+ *
+ * This function applies the user configuration to the PRU I2S driver.
+ * It must be called before PRUI2S_init().
+ *
+ * \return 0 on success, negative error code on failure
+ */
+int32_t PRUI2S_applyAppConfig(void)
+{
+ int32_t status = PRUI2S_DRV_SOK;
+ uint8_t i;
+
+ for (i = 0; i < PRU_I2S_NUM_CONFIG; i++)
+ {
+ status = PRUI2S_setUserConfig(
+ i,
+ gPruI2sAppConfig[i].icssInstId,
+ gPruI2sAppConfig[i].pruInstId
+ );
+
+ if (status != PRUI2S_DRV_SOK)
+ {
+ break;
+ }
+ }
+
+ return status;
+}
diff --git a/examples/pru_i2s/pru_i2s_app/pru_i2s_app_config.h b/examples/pru_i2s/pru_i2s_app/pru_i2s_app_config.h
new file mode 100644
index 000000000..cc4ac8ec3
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/pru_i2s_app_config.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2024-2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PRU_I2S_APP_CONFIG_H_
+#define _PRU_I2S_APP_CONFIG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+/* ========================================================================== */
+/* I2S MODE CONFIGURATION CONSTANTS */
+/* ========================================================================== */
+
+#define I2S_MODE 0 /**< Standard I2S mode */
+#define TDM_MODE 1 /**< Time Division Multiplexing mode */
+#define CONFIG_I2S0_MODE TDM_MODE /**< Selected mode: TDM mode=1, I2S mode=0 */
+
+/* ========================================================================== */
+/* SYSCONFIG-BASED INSTANCE ENABLE FLAGS */
+/* ========================================================================== */
+
+#ifndef CONFIG_PRU_I2S0_ENABLED
+#define CONFIG_PRU_I2S0_ENABLED 1 /**< Enable PRU I2S 0 (Tx on PRU0) */
+#endif
+
+#ifndef CONFIG_PRU_I2S1_ENABLED
+#define CONFIG_PRU_I2S1_ENABLED 1 /**< Enable PRU I2S 1 (Rx on PRU1) */
+#endif
+
+/* ========================================================================== */
+/* PRU I2S INSTANCE INDICES */
+/* ========================================================================== */
+
+#define PRU_I2S0_INSTANCE_IDX 0 /**< Instance index for PRU I2S 0 (Tx only) */
+#define PRU_I2S1_INSTANCE_IDX 1 /**< Instance index for PRU I2S 1 (Rx only) */
+
+/* ========================================================================== */
+/* TEST INSTANCE INDICES - PRU I2S INSTANCES USED */
+/* ========================================================================== */
+
+#define TEST_PRUI2S0_IDX PRU_I2S0_INSTANCE_IDX /**< Test PRU I2S 0 index (for Tx) */
+#define TEST_PRUI2S1_IDX PRU_I2S1_INSTANCE_IDX /**< Test PRU I2S 1 index (for Rx) */
+
+/* ========================================================================== */
+/* FUNCTION DECLARATIONS */
+/* ========================================================================== */
+
+/**
+ * \brief Apply PRU I2S application configuration
+ *
+ * This function applies the user configuration to the PRU I2S driver.
+ * It must be called before PRUI2S_init().
+ *
+ * \return 0 on success, negative error code on failure
+ */
+int32_t PRUI2S_applyAppConfig(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PRU_I2S_APP_CONFIG_H_ */
diff --git a/examples/pru_i2s/pru_i2s_app/pru_i2s_diagnostic.c b/examples/pru_i2s/pru_i2s_app/pru_i2s_diagnostic.c
new file mode 100644
index 000000000..2a2bc17be
--- /dev/null
+++ b/examples/pru_i2s/pru_i2s_app/pru_i2s_diagnostic.c
@@ -0,0 +1,1427 @@
+/*
+ * Copyright (C) 2024-2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file pru_i2s_diagnostic.c
+ *
+ * \brief PRU I2S diagnostic application demonstrating real-time audio streaming
+ *
+ * \details This application provides a comprehensive diagnostic interface for testing
+ * and validating PRU I2S audio communication. It demonstrates:
+ * - Real-time audio streaming over I2S/TDM interfaces
+ * - Ping-pong buffer management for continuous data flow
+ * - Multi-channel audio Tx/Rx operations
+ * - Error detection and reporting
+ * - ISR-based interrupt handling for low-latency operation
+ *
+ * ## Application Flow
+ *
+ * The application follows this sequence:
+ *
+ * **STEP 1: System Initialization**
+ * - Initialize SoC drivers (UART, I2C, etc.)
+ * - Set up board peripherals and IO configuration
+ *
+ * **STEP 2: PRU-ICSS Subsystem Initialization**
+ * - Open PRU-ICSS instance using SysConfig-generated configuration
+ * - Disable PRU cores before firmware load
+ * - Clear PRU data memory regions using PRUICSS_initMemory
+ * - Initialize INTC (Interrupt Controller) using SysConfig data
+ *
+ * **STEP 3: Semaphore Initialization**
+ * - Create binary semaphores for Tx/Rx synchronization
+ * - Used for ISR-to-task communication pattern (required for streaming protocols)
+ *
+ * **STEP 4: PRU I2S Driver Initialization**
+ * - Initialize PRU I2S driver parameters
+ * - Configure ping-pong buffer addresses and sizes
+ * - Register ISR callback functions for Tx, Rx, and error interrupts
+ * - Open PRU I2S instances (separate for Tx and Rx)
+ *
+ * **STEP 5: Firmware Loading and PRU Core Enablement**
+ * - Load PRU I2S firmware binaries to PRU instruction and data memory
+ * - Reset PRU cores to initialize state
+ * - Enable PRU cores to begin audio streaming
+ * - Display firmware version information
+ *
+ * **STEP 6: Real-Time Audio Streaming Loop**
+ * - Mode selection based on enabled instances:
+ * - Full-duplex: Both Tx and Rx enabled (simultaneous transmit/receive)
+ * - Half-duplex Tx-only: Only Tx enabled (transmit only)
+ * - Half-duplex Rx-only: Only Rx enabled (receive only)
+ * - Continuous loop for ping-pong buffer processing
+ * - Wait for semaphore signals from Tx/Rx ISRs
+ * - Read received audio data from Rx buffers (if Rx enabled)
+ * - Write transmit audio data to Tx buffers (if Tx enabled)
+ * - Update buffer pointers for next iteration
+ * - Monitor and report error conditions
+ *
+ * **STEP 7: Cleanup and Shutdown**
+ * - Close PRU I2S driver instances
+ * - Deinitialize drivers and release resources
+ * - Destruct semaphores
+ * - Close board and system drivers
+ *
+ * ## Semaphore Usage Pattern
+ *
+ * The application uses **semaphores for ISR-to-task synchronization** because:
+ * - I2S is a **continuous streaming protocol** (not query-based like position encoders)
+ * - Data arrives/departs at fixed sample rate (e.g., 48 kHz)
+ * - Must process EVERY ping-pong buffer swap - missing a buffer = audio glitch
+ * - Semaphores allow task to sleep during idle, improving CPU efficiency
+ * - Industry standard pattern for all audio drivers (ALSA, ASIO, CoreAudio)
+ *
+ * This is fundamentally different from encoder protocols (EnDAT, HDSL, BiSS-C) which
+ * use polling because they are query-based (on-demand reads at lower rates).
+ *
+ * ## Error Handling Strategy
+ *
+ * The application follows these error handling principles:
+ * - All driver API calls check return values for detailed error codes
+ * - Error counters track cumulative failures (Tx/Rx errors, interrupt clear errors)
+ * - Periodic error logging (first occurrence + every Nth occurrence)
+ * - Timeout detection on semaphore waits indicates stream failure
+ * - Error threshold detection terminates loop to prevent indefinite error states
+ * - Uses DebugP_assert for critical initialization failures
+ *
+ * ## Driver Validation Strategy
+ *
+ * The PRU I2S driver uses optimized validation:
+ * - **Handle validation**: All public APIs validate handle for NULL
+ * - **Buffer address validation**: Ping-pong buffer addresses validated during open
+ * - **Parameter range checking**: Buffer sizes, channel counts validated against limits
+ * - **PRUICSS handle validation**: Ensures valid PRUICSS subsystem access
+ *
+ * ## Configuration Notes
+ *
+ * - All PRU I2S configuration parameters are set via application config files
+ * - INTC mapping is defined in SysConfig
+ * - Firmware selection is automatic based on I2S/TDM mode
+ * - Buffer sizes must match firmware expectations
+ */
+
+
+/* ========================================================================== */
+/* Include Files */
+/* ========================================================================== */
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "ti_drivers_config.h"
+#include "ti_drivers_open_close.h"
+#include "ti_board_open_close.h"
+#include "data.h"
+#include "pru_i2s_drv.h"
+#include "pru_i2s_app_config.h"
+
+#ifdef SOC_AM263X
+#include "board/ioexp_tca6416.h"
+#endif
+
+/* Firmware selection based on mode and enabled instances */
+/* Include firmware only for enabled instances */
+#if (CONFIG_I2S0_MODE == TDM_MODE)
+ /* TDM Mode firmware */
+ #if defined(CONFIG_PRU_I2S0_ENABLED) && (CONFIG_PRU_I2S0_ENABLED == 1)
+ #include "TDM4/pru_i2s_tdm4_pru0_array.h" /* PRU0 TDM firmware */
+ #endif
+ #if defined(CONFIG_PRU_I2S1_ENABLED) && (CONFIG_PRU_I2S1_ENABLED == 1)
+ #include "TDM4/pru_i2s_tdm4_pru1_array.h" /* PRU1 TDM firmware */
+ #endif
+#else
+ /* I2S Mode firmware */
+ #if defined(CONFIG_PRU_I2S0_ENABLED) && (CONFIG_PRU_I2S0_ENABLED == 1)
+ #include "I2S/pru_i2s_pru0_array.h" /* PRU0 I2S firmware */
+ #endif
+ #if defined(CONFIG_PRU_I2S1_ENABLED) && (CONFIG_PRU_I2S1_ENABLED == 1)
+ #include "I2S/pru_i2s_pru1_array.h" /* PRU1 I2S firmware */
+ #endif
+#endif
+
+/* ========================================================================== */
+/* Macros & Typedefs */
+/* ========================================================================== */
+
+/* Optional Rx-to-Tx loopback for testing */
+/* #define _DBG_PRUI2S_RX_TO_TX_LB */
+
+/* ========================================================================== */
+/* Global Variables */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* Global Variables */
+/* ========================================================================== */
+
+/* PRU-ICSS driver handle */
+PRUICSS_Handle gPruIcssHandle = NULL;
+
+/* PRU I2S driver handles */
+PRUI2S_Handle gHPruI2s0 = NULL; /* Tx instance */
+PRUI2S_Handle gHPruI2s1 = NULL; /* Rx instance */
+
+/* Rx & Tx semaphores for ISR-to-task synchronization */
+SemaphoreP_Object gPruI2s0TxSemObj;
+SemaphoreP_Object gPruI2s1RxSemObj;
+Bool gSemaphoresInitialized = FALSE;
+
+/* Audio buffer storage - gPruI2s1RxPingPongBuf and gPruI2s0TxBuf defined in data.h */
+__attribute__((section(".RxBuf"))) int32_t gPruI2s0RxBuf[RX_BUF_SZ_32B];
+__attribute__((section(".RxBuf"))) int32_t gPruI2s1RxBuf[RX_BUF_SZ_32B];
+
+/* PRU I2S buffer control variables */
+int32_t *gPPruI2s0TxBuf; /* PRU I2S 0 transmit buffer pointer */
+uint32_t gPruI2s0TxCnt; /* PRU I2S 0 transmit count (all channels) */
+uint16_t gPruI2s0XferSz; /* PRU I2S 0 transfer size in 32-bit words */
+
+int32_t *gPPruI2s1RxBuf; /* PRU I2S 1 receive buffer pointer */
+uint32_t gPruI2s1RxCnt; /* PRU I2S 1 receive count (all channels) */
+uint16_t gPruI2s1XferSz; /* PRU I2S 1 transfer size in 32-bit words */
+
+/* Error and debug statistics */
+/* PRU I2S 0 Tx ISR */
+uint32_t gPruI2s0TxIsrCnt=0; /* PRU I2S 0 Tx ISR (IRQ) count */
+uint32_t gPruI2s0ClrTxIntErrCnt=0; /* PRU I2S 0 clear Tx interrupt error count */
+uint32_t gPruI2s0WrtErrCnt=0; /* PRU I2S 0 write error count */
+/* PRU I2S 0 error ISR */
+uint32_t gPruI2s0ErrIsrCnt=0; /* PRU I2S 0 error ISR (IRQ) count */
+uint32_t gPruI2s0ClrErrIntErrCnt=0; /* PRU I2S 0 clear error interrupt error count */
+uint32_t gPruI2s0ErrOvrCnt=0; /* PRU I2S 0 Rx overflow error count */
+uint32_t gPruI2s0ErrUndCnt=0; /* PRU I2S 0 Tx underflow error count */
+uint32_t gPruI2s0ErrFsyncCnt=0; /* PRU I2S 0 frame sync error count */
+
+/* PRU I2S 1 Rx ISR */
+uint32_t gPruI2s1RxIsrCnt=0; /* PRU I2S 1 Rx ISR (IRQ) count */
+uint32_t gPruI2s1ClrRxIntErrCnt=0; /* PRU I2S 1 clear Rx interrupt error count */
+uint32_t gPruI2s1RdErrCnt=0; /* PRU I2S 1 read error count */
+/* PRU I2S 1 error ISR */
+uint32_t gPruI2s1ErrIsrCnt=0; /* PRU I2S 1 error ISR (IRQ) count */
+uint32_t gPruI2s1ClrErrIntErrCnt=0; /* PRU I2S 1 clear error interrupt error count */
+uint32_t gPruI2s1ErrOvrCnt=0; /* PRU I2S 1 Rx overflow error count */
+
+/* PRU firmware image information */
+/* ========================================================================== */
+/* Structure Declarations */
+/* ========================================================================== */
+
+/* PRU I2S PRU image info */
+static PRUI2S_PruFwImageInfo gPruFwImageInfo[PRU_I2S_NUM_PRU_IMAGE] =
+{
+ {pru_prupru_i2s0_image_0_0, pru_prupru_i2s0_image_0_1, sizeof(pru_prupru_i2s0_image_0_0), sizeof(pru_prupru_i2s0_image_0_1)},
+ {pru_prupru_i2s1_image_0_0, pru_prupru_i2s1_image_0_1, sizeof(pru_prupru_i2s1_image_0_0), sizeof(pru_prupru_i2s1_image_0_1)}
+};
+
+
+/* ========================================================================== */
+/* Function Declarations */
+/* ========================================================================== */
+
+/* Function Declarations */
+/* ========================================================================== */
+
+/* Initialization functions */
+static void prui2s_pruicss_init(void);
+static void prui2s_pruicss_load_run_fw(void);
+static void prui2s_display_fw_version(uint8_t pruSlice);
+static int32_t prui2s_init_semaphores(void);
+static int32_t prui2s_init_instance(uint8_t instanceIdx, PRUI2S_Handle *pHandle);
+#ifdef SOC_AM263X
+static void prui2s_board_io_expander_init(void);
+#endif
+
+/* Runtime operation functions */
+static void prui2s_streaming_loop_full_duplex(PRUI2S_Handle hTx, PRUI2S_Handle hRx);
+static void prui2s_streaming_loop_tx_only(PRUI2S_Handle hTx);
+static void prui2s_streaming_loop_rx_only(PRUI2S_Handle hRx);
+static void prui2s_display_statistics(void);
+static void prui2s_display_configuration(void);
+
+/* Cleanup functions */
+static void prui2s_cleanup_semaphores(void);
+static void prui2s_cleanup_instances(void);
+
+/* ISR handlers */
+void pruI2s0TxIrqHandler(void *args);
+void pruI2s0ErrIrqHandler(void *args);
+void pruI2s1RxIrqHandler(void *args);
+void pruI2s1ErrIrqHandler(void *args);
+
+
+/* ========================================================================== */
+/* Function Definitions */
+/* ========================================================================== */
+
+uint32_t gPruI2s1ErrUndCnt=0; /* PRU I2S 1 Tx underflow error count */
+uint32_t gPruI2s1ErrFsyncCnt=0; /* PRU I2S 1 frame sync error count */
+
+volatile Bool gRunFlag = TRUE; /* Flag for continuing to execute test */
+uint32_t gLoopCnt;
+
+/* Optional Rx-to-Tx loopback mode */
+#ifdef _DBG_PRUI2S_RX_TO_TX_LB
+uint8_t gPruI2s1NumRxI2s;
+uint8_t gPruI2s0NumTxI2s;
+float gPruI2s0LGain = GAIN_MINUS_3DB; /* PRU I2S 0 Left channel gain, -3 dB */
+float gPruI2s0RGain = GAIN_MINUS_6DB; /* PRU I2S 0 Right channel gain, -6 dB */
+#endif
+
+/* ========================================================================== */
+/* Function Definitions */
+/* ========================================================================== */
+
+/**
+ * \brief Initialize PRU-ICSS subsystem for PRU I2S operation
+ *
+ * \details Performs PRU-ICSS initialization including:
+ * - Open PRU-ICSS handle using SysConfig-generated configuration
+ * - Clear PRU data RAM regions using PRUICSS_initMemory
+ * - Disable PRU cores before firmware load
+ *
+ * This function must be called before loading PRU firmware and opening PRU I2S instances.
+ */
+static void prui2s_pruicss_init(void)
+{
+ int32_t status = SystemP_FAILURE;
+ uint32_t u_status = 0;
+ uint8_t pru0_id = PRUICSS_PRU0;
+ uint8_t pru1_id = PRUICSS_PRU1;
+
+ /* Open PRU-ICSS instance from SysConfig (ICSSM1) */
+ gPruIcssHandle = PRUICSS_open(CONFIG_PRU_ICSS0);
+ if(gPruIcssHandle == NULL)
+ {
+ DebugP_log("\r\n ERROR: PRUICSS_open failed - NULL handle returned\n");
+ DebugP_assert(0);
+ }
+
+ /* Disable PRU0 core */
+ status = PRUICSS_disableCore(gPruIcssHandle, pru0_id);
+ DebugP_assert(SystemP_SUCCESS == status);
+
+ /* Disable PRU1 core */
+ status = PRUICSS_disableCore(gPruIcssHandle, pru1_id);
+ DebugP_assert(SystemP_SUCCESS == status);
+
+ /* Clear PRU-ICSS DATA RAM for PRU0 slice */
+ u_status = PRUICSS_initMemory(gPruIcssHandle, PRUICSS_DATARAM(0));
+ DebugP_assert(0 != u_status);
+
+ /* Clear PRU-ICSS DATA RAM for PRU1 slice */
+ u_status = PRUICSS_initMemory(gPruIcssHandle, PRUICSS_DATARAM(1));
+ DebugP_assert(0 != u_status);
+
+ /* Configure PRU-ICSS Interrupt Controller */
+ /* INTC data is declared in ti_drivers_config.h based on SoC:
+ - AM263x uses icss0_intc_initdata (ICSS instance 0)
+ - AM261x uses icss1_intc_initdata (ICSS instance 1) */
+#ifdef SOC_AM263X
+ status = PRUICSS_intcInit(gPruIcssHandle, &icss0_intc_initdata);
+#else
+ status = PRUICSS_intcInit(gPruIcssHandle, &icss1_intc_initdata);
+#endif
+ DebugP_assert(SystemP_SUCCESS == status);
+}
+
+/**
+ * \brief Load and execute PRU I2S firmware
+ *
+ * \details This function handles the complete firmware loading sequence for enabled PRU cores:
+ * - Disable PRU core
+ * - Write firmware binary to PRU instruction RAM
+ * - Validate load success
+ * - Reset PRU core
+ * - Enable PRU core to begin execution
+ *
+ * The firmware binaries are selected based on SysConfig-enabled instances.
+ * Only enabled instances (CONFIG_PRU_I2S0_ENABLED, CONFIG_PRU_I2S1_ENABLED) are loaded.
+ */
+static void prui2s_pruicss_load_run_fw(void)
+{
+ int32_t status = SystemP_FAILURE;
+ uint32_t u_status = 0;
+
+#if defined(CONFIG_PRU_I2S0_ENABLED) && (CONFIG_PRU_I2S0_ENABLED == 1)
+ /* ============================================ */
+ /* Load PRU0 firmware (Tx) */
+ /* ============================================ */
+ const uint32_t *pru0_firmware = gPruFwImageInfo[0].pPruImemImg;
+ uint32_t pru0_firmware_size = gPruFwImageInfo[0].pruImemImgSz;
+ uint8_t pru0_id = PRUICSS_PRU0;
+
+ /* Disable PRU0 core */
+ status = PRUICSS_disableCore(gPruIcssHandle, pru0_id);
+ DebugP_assert(SystemP_SUCCESS == status);
+
+ /* Load firmware to PRU0 instruction RAM */
+ u_status = PRUICSS_writeMemory(gPruIcssHandle, PRUICSS_IRAM_PRU(0), 0,
+ (uint32_t *)pru0_firmware, pru0_firmware_size);
+ DebugP_assert(0 != u_status);
+
+ /* DMEM is cleared by PRUICSS_initMemory() earlier - skip explicit DMEM write
+ * to avoid hardware timeout issues. The firmware will initialize DMEM at runtime. */
+
+ /* Reset PRU0 core */
+ status = PRUICSS_resetCore(gPruIcssHandle, pru0_id);
+ DebugP_assert(SystemP_SUCCESS == status);
+
+ /* Enable PRU0 core to run firmware */
+ status = PRUICSS_enableCore(gPruIcssHandle, pru0_id);
+ DebugP_assert(SystemP_SUCCESS == status);
+#endif
+
+#if defined(CONFIG_PRU_I2S1_ENABLED) && (CONFIG_PRU_I2S1_ENABLED == 1)
+ /* ============================================ */
+ /* Load PRU1 firmware (Rx) */
+ /* ============================================ */
+ const uint32_t *pru1_firmware = gPruFwImageInfo[1].pPruImemImg;
+ uint32_t pru1_firmware_size = gPruFwImageInfo[1].pruImemImgSz;
+ uint8_t pru1_id = PRUICSS_PRU1;
+
+ /* Disable PRU1 core */
+ status = PRUICSS_disableCore(gPruIcssHandle, pru1_id);
+ DebugP_assert(SystemP_SUCCESS == status);
+
+ /* Load firmware to PRU1 instruction RAM */
+ u_status = PRUICSS_writeMemory(gPruIcssHandle, PRUICSS_IRAM_PRU(1), 0,
+ (uint32_t *)pru1_firmware, pru1_firmware_size);
+ DebugP_assert(0 != u_status);
+
+ /* DMEM is cleared by PRUICSS_initMemory() earlier - skip explicit DMEM write
+ * to avoid hardware timeout issues. The firmware will initialize DMEM at runtime. */
+
+ /* Reset PRU1 core */
+ status = PRUICSS_resetCore(gPruIcssHandle, pru1_id);
+ DebugP_assert(SystemP_SUCCESS == status);
+
+ /* Enable PRU1 core to run firmware */
+ status = PRUICSS_enableCore(gPruIcssHandle, pru1_id);
+ DebugP_assert(SystemP_SUCCESS == status);
+#endif
+}
+
+/**
+ * \brief Display PRU I2S firmware version information
+ *
+ * \param pruSlice PRU core slice (0 or 1)
+ */
+static void prui2s_display_fw_version(uint8_t pruSlice)
+{
+ uint32_t version;
+ const uint32_t *pFwImage;
+
+ /* Get firmware image based on PRU slice */
+ if(pruSlice == PRUICSS_PRU0)
+ {
+ pFwImage = gPruFwImageInfo[0].pPruImemImg;
+ }
+ else
+ {
+ pFwImage = gPruFwImageInfo[1].pPruImemImg;
+ }
+
+ /* Firmware version is stored at offset 1 in IMEM */
+ version = pFwImage[1];
+
+ DebugP_log("PRU I2S PRU%d Firmware: %x.%x.%x (%s)\r\n",
+ pruSlice,
+ (version >> 24) & 0x7F,
+ (version >> 16) & 0xFF,
+ version & 0xFFFF,
+ version & (1 << 31) ? "internal" : "release");
+}
+
+/**
+ * \brief Initialize semaphores for ISR-to-task synchronization
+ *
+ * \return SystemP_SUCCESS on success, SystemP_FAILURE on error
+ */
+static int32_t prui2s_init_semaphores(void)
+{
+ int32_t status;
+
+ /* Construct binary semaphore for Tx completion */
+ status = SemaphoreP_constructBinary(&gPruI2s0TxSemObj, 0);
+ if (status != SystemP_SUCCESS)
+ {
+ DebugP_log("ERROR: SemaphoreP_constructBinary() gPruI2s0TxSemObj failed\r\n");
+ return SystemP_FAILURE;
+ }
+
+ /* Construct binary semaphore for Rx completion */
+ status = SemaphoreP_constructBinary(&gPruI2s1RxSemObj, 0);
+ if (status != SystemP_SUCCESS)
+ {
+ DebugP_log("ERROR: SemaphoreP_constructBinary() gPruI2s1RxSemObj failed\r\n");
+ SemaphoreP_destruct(&gPruI2s0TxSemObj);
+ return SystemP_FAILURE;
+ }
+
+ gSemaphoresInitialized = TRUE;
+ DebugP_log("Semaphores initialized successfully\r\n");
+ return SystemP_SUCCESS;
+}
+
+/**
+ * \brief Initialize single PRU I2S instance
+ *
+ * \param instanceIdx Instance index (TEST_PRUI2S0_IDX or TEST_PRUI2S1_IDX)
+ * \param pHandle Pointer to store opened handle
+ *
+ * \return SystemP_SUCCESS on success, SystemP_FAILURE on error
+ */
+static int32_t prui2s_init_instance(uint8_t instanceIdx, PRUI2S_Handle *pHandle)
+{
+ PRUI2S_Params prms;
+ PRUI2S_SwipAttrs swipAttrs;
+ int32_t status;
+
+ /* Get SWIP attributes for this instance */
+ status = PRUI2S_getInitCfg(instanceIdx, &swipAttrs);
+ if (status != PRUI2S_DRV_SOK)
+ {
+ DebugP_log("ERROR: PRUI2S_getInitCfg() instance %d failed\r\n", instanceIdx);
+ return SystemP_FAILURE;
+ }
+
+ /* Initialize parameters with defaults */
+ PRUI2S_paramsInit(&prms);
+
+ /* Set PRUICSS handle (required for base address calculation) */
+ prms.pruicss_handle = gPruIcssHandle;
+
+ /* Configure instance-specific parameters */
+ if(instanceIdx == TEST_PRUI2S0_IDX)
+ {
+ /* PRU I2S 0 - Tx only */
+ DebugP_assert((swipAttrs.numTxI2s > 0) && (swipAttrs.numRxI2s == 0));
+
+ gPruI2s0XferSz = PRUI2S0_TX_PING_PONG_BUF_SZ_32B/PING_PONG_BUFFER_COUNT;
+
+ prms.rxPingPongBaseAddr = 0;
+ prms.txPingPongBaseAddr = (uint32_t)PRUI2S0_TX_PING_PONG_BASE_ADDR;
+ prms.pingPongBufSz = PRUI2S0_TX_PING_PONG_BUF_SZ;
+ prms.i2sTxCallbackFxn = &pruI2s0TxIrqHandler;
+ prms.i2sRxCallbackFxn = NULL;
+ prms.i2sErrCallbackFxn = &pruI2s0ErrIrqHandler;
+
+ gPPruI2s0TxBuf = &gPruI2s0TxBuf[0];
+ gPruI2s0TxCnt = 0;
+
+#ifdef _DBG_PRUI2S_RX_TO_TX_LB
+ gPruI2s0NumTxI2s = swipAttrs.numTxI2s;
+#endif
+ }
+ else
+ {
+ /* PRU I2S 1 - Rx only */
+ DebugP_assert((swipAttrs.numTxI2s == 0) && (swipAttrs.numRxI2s > 0));
+
+ gPruI2s1XferSz = PRUI2S1_RX_PING_PONG_BUF_SZ_32B/PING_PONG_BUFFER_COUNT;
+
+ prms.rxPingPongBaseAddr = (uint32_t)gPruI2s1RxPingPongBuf;
+ prms.txPingPongBaseAddr = 0;
+ prms.pingPongBufSz = PRUI2S1_RX_PING_PONG_BUF_SZ;
+ prms.i2sTxCallbackFxn = NULL;
+ prms.i2sRxCallbackFxn = &pruI2s1RxIrqHandler;
+ prms.i2sErrCallbackFxn = &pruI2s1ErrIrqHandler;
+
+ gPPruI2s1RxBuf = &gPruI2s1RxBuf[0];
+ gPruI2s1RxCnt = 0;
+
+#ifdef _DBG_PRUI2S_RX_TO_TX_LB
+ gPruI2s1NumRxI2s = swipAttrs.numRxI2s;
+#endif
+ }
+
+ /* Open PRU I2S instance */
+ *pHandle = PRUI2S_open(instanceIdx, &prms);
+ if (*pHandle == NULL)
+ {
+ DebugP_log("ERROR: PRUI2S_open() instance %d failed\r\n", instanceIdx);
+ return SystemP_FAILURE;
+ }
+
+ DebugP_log("PRU I2S instance %d initialized (Tx:%d, Rx:%d channels)\r\n",
+ instanceIdx, swipAttrs.numTxI2s, swipAttrs.numRxI2s);
+
+ return SystemP_SUCCESS;
+}
+
+#ifdef SOC_AM263X
+/**
+ * \brief Configure I2C IO Expander for board signal routing
+ *
+ * \details Routes PRU signals to HSEC connector by configuring:
+ * - ICSSM1_MUX_SEL = 1
+ * - ICSSM2_MUX_SEL = 1
+ * Routes PR0_PRUn_GPOmm signals to HSEC
+ *
+ * \note This is board-specific configuration and may vary per platform
+ */
+static void prui2s_board_io_expander_init(void)
+{
+ int32_t status = SystemP_SUCCESS;
+ uint32_t ioIndex;
+ TCA6416_Config gTCA6416_Config;
+ TCA6416_Params tca6416Params;
+
+ TCA6416_Params_init(&tca6416Params);
+ status = TCA6416_open(&gTCA6416_Config, &tca6416Params);
+
+ if(status == SystemP_SUCCESS)
+ {
+ /* Configure P02 as output and set HIGH */
+ ioIndex = IOEXP_INDEX_P02;
+ status = TCA6416_config(&gTCA6416_Config, ioIndex, TCA6416_MODE_OUTPUT);
+ status += TCA6416_setOutput(&gTCA6416_Config, ioIndex, TCA6416_OUT_STATE_HIGH);
+
+ /* Configure P03 as output and set HIGH */
+ ioIndex = IOEXP_INDEX_P03;
+ status += TCA6416_config(&gTCA6416_Config, ioIndex, TCA6416_MODE_OUTPUT);
+ status += TCA6416_setOutput(&gTCA6416_Config, ioIndex, TCA6416_OUT_STATE_HIGH);
+
+ if(status != SystemP_SUCCESS)
+ {
+ DebugP_log("WARNING: I2C IO Expander configuration failed\r\n");
+ }
+ else
+ {
+ DebugP_log("I2C IO Expander configured successfully\r\n");
+ }
+ }
+ else
+ {
+ DebugP_log("WARNING: TCA6416_open failed\r\n");
+ }
+
+ TCA6416_close(&gTCA6416_Config);
+}
+#endif
+
+/**
+ * \brief Real-time audio streaming loop with ping-pong buffer processing
+ *
+ * \param hTx PRU I2S Tx instance handle
+ * \param hRx PRU I2S Rx instance handle
+ *
+ * \details Continuous loop that:
+ * - Writes next Tx buffer
+ * - Waits for Rx and Tx completion via semaphores
+ * - Reads next Rx buffer
+ * - Updates buffer pointers
+ * - Monitors error conditions
+ */
+static void prui2s_streaming_loop_full_duplex(PRUI2S_Handle hTx, PRUI2S_Handle hRx)
+{
+ PRUI2S_IoBuf rdIoBuf;
+ PRUI2S_IoBuf wrtIoBuf;
+ int32_t status;
+
+ gLoopCnt = 0;
+ gRunFlag = TRUE;
+
+ DebugP_log("\r\nStarting real-time audio streaming loop (FULL-DUPLEX mode)...\r\n");
+ DebugP_log("Press Ctrl+C to stop\r\n\r\n");
+
+ while (gRunFlag == TRUE)
+ {
+ /* Write next PRU I2S0 Tx ping/pong buffer */
+ PRUI2S_ioBufInit(&wrtIoBuf);
+ wrtIoBuf.ioBufAddr = gPPruI2s0TxBuf;
+ status = PRUI2S_write(hTx, &wrtIoBuf);
+ if (status != PRUI2S_DRV_SOK)
+ {
+ gPruI2s0WrtErrCnt++;
+ if (gPruI2s0WrtErrCnt == 1 || (gPruI2s0WrtErrCnt % ERROR_LOG_INTERVAL) == 0)
+ {
+ DebugP_log("ERROR: PRU I2S0 write error (count: %d)\r\n", gPruI2s0WrtErrCnt);
+ }
+ if (gPruI2s0WrtErrCnt > ERROR_COUNT_THRESHOLD)
+ {
+ DebugP_log("ERROR: PRU I2S0 write error count exceeded threshold\r\n");
+ gRunFlag = FALSE;
+ continue;
+ }
+ }
+
+ /* Wait for Rx interrupt with timeout */
+ status = SemaphoreP_pend(&gPruI2s1RxSemObj, SEMAPHORE_TIMEOUT_MS);
+ if (status != SystemP_SUCCESS)
+ {
+ DebugP_log("ERROR: Timeout waiting for PRU I2S1 Rx event\r\n");
+ gRunFlag = FALSE;
+ continue;
+ }
+
+ /* Wait for Tx interrupt with timeout */
+ status = SemaphoreP_pend(&gPruI2s0TxSemObj, SEMAPHORE_TIMEOUT_MS);
+ if (status != SystemP_SUCCESS)
+ {
+ DebugP_log("ERROR: Timeout waiting for PRU I2S0 Tx event\r\n");
+ gRunFlag = FALSE;
+ continue;
+ }
+
+ gLoopCnt++;
+
+ /* Read next PRU I2S1 Rx ping/pong buffer */
+ PRUI2S_ioBufInit(&rdIoBuf);
+ rdIoBuf.ioBufAddr = gPPruI2s1RxBuf;
+ status = PRUI2S_read(hRx, &rdIoBuf);
+ if (status != PRUI2S_DRV_SOK)
+ {
+ gPruI2s1RdErrCnt++;
+ if (gPruI2s1RdErrCnt == 1 || (gPruI2s1RdErrCnt % ERROR_LOG_INTERVAL) == 0)
+ {
+ DebugP_log("ERROR: PRU I2S1 read error (count: %d)\r\n", gPruI2s1RdErrCnt);
+ }
+ if (gPruI2s1RdErrCnt > ERROR_COUNT_THRESHOLD)
+ {
+ DebugP_log("ERROR: PRU I2S1 read error count exceeded threshold\r\n");
+ gRunFlag = FALSE;
+ continue;
+ }
+ }
+
+#ifdef _DBG_PRUI2S_RX_TO_TX_LB
+ /* Optional: Rx-to-Tx loopback with gain/mixing */
+ int32_t *pSrc32b = gPPruI2s1RxBuf;
+ int32_t *pDst32b = gPPruI2s0TxBuf;
+ for (uint16_t i = 0; i < gPruI2s0XferSz/(2*gPruI2s0NumTxI2s); i++)
+ {
+ /* Compute Tx left-ch outputs with gain */
+ pDst32b[0] = (int32_t)(pSrc32b[0] * gPruI2s0LGain);
+ pDst32b[1] = (int32_t)(pSrc32b[1] * gPruI2s0LGain);
+ pDst32b[2] = (int32_t)((pSrc32b[0] + pSrc32b[1])/CHANNEL_MIX_DIVISOR);
+ pSrc32b += gPruI2s1NumRxI2s;
+ pDst32b += gPruI2s0NumTxI2s;
+
+ /* Compute Tx right-ch outputs with gain */
+ pDst32b[0] = (int32_t)(pSrc32b[0] * gPruI2s0RGain);
+ pDst32b[1] = (int32_t)(pSrc32b[1] * gPruI2s0RGain);
+ pDst32b[2] = (int32_t)((pSrc32b[0] + pSrc32b[1])/CHANNEL_MIX_DIVISOR);
+ pSrc32b += gPruI2s1NumRxI2s;
+ pDst32b += gPruI2s0NumTxI2s;
+ }
+#endif
+
+ /* Update Rx buffer pointer with wraparound */
+ gPruI2s1RxCnt += gPruI2s1XferSz;
+ gPPruI2s1RxBuf += gPruI2s1XferSz;
+ if (gPruI2s1RxCnt >= RX_BUF_SZ_32B)
+ {
+ gPPruI2s1RxBuf = &gPruI2s1RxBuf[0];
+ gPruI2s1RxCnt = 0;
+ }
+
+ /* Update Tx buffer pointer with wraparound */
+ gPruI2s0TxCnt += gPruI2s0XferSz;
+ gPPruI2s0TxBuf += gPruI2s0XferSz;
+ if (gPruI2s0TxCnt >= TX_BUF_SZ_32B)
+ {
+ gPPruI2s0TxBuf = &gPruI2s0TxBuf[0];
+ gPruI2s0TxCnt = 0;
+ }
+
+ /* Display periodic progress (every 1000 iterations) */
+ if ((gLoopCnt % 1000) == 0)
+ {
+ DebugP_log("Streaming: %d iterations completed\r", gLoopCnt);
+ }
+ }
+
+ DebugP_log("\r\nStreaming loop terminated after %d iterations\r\n", gLoopCnt);
+}
+
+/**
+ * \brief Real-time audio streaming loop (Tx-only mode)
+ *
+ * \param hTx Handle to PRU I2S Tx instance
+ *
+ * \details Tx-only streaming loop for half-duplex transmit operation that:
+ * - Writes Tx buffers
+ * - Waits for Tx interrupt via semaphore
+ * - Updates buffer pointers with wraparound
+ * - Displays periodic progress
+ * - Monitors error conditions
+ */
+static void prui2s_streaming_loop_tx_only(PRUI2S_Handle hTx)
+{
+ PRUI2S_IoBuf wrtIoBuf;
+ int32_t status;
+
+ gLoopCnt = 0;
+ gRunFlag = TRUE;
+
+ DebugP_log("\r\nStarting real-time audio streaming loop (TX-ONLY mode)...\r\n");
+ DebugP_log("Press Ctrl+C to stop\r\n\r\n");
+
+ while (gRunFlag == TRUE)
+ {
+ /* Write next PRU I2S0 Tx ping/pong buffer */
+ PRUI2S_ioBufInit(&wrtIoBuf);
+ wrtIoBuf.ioBufAddr = gPPruI2s0TxBuf;
+ status = PRUI2S_write(hTx, &wrtIoBuf);
+ if (status != PRUI2S_DRV_SOK)
+ {
+ gPruI2s0WrtErrCnt++;
+ if (gPruI2s0WrtErrCnt == 1 || (gPruI2s0WrtErrCnt % ERROR_LOG_INTERVAL) == 0)
+ {
+ DebugP_log("ERROR: PRU I2S0 write error (count: %d)\r\n", gPruI2s0WrtErrCnt);
+ }
+ if (gPruI2s0WrtErrCnt > ERROR_COUNT_THRESHOLD)
+ {
+ DebugP_log("ERROR: PRU I2S0 write error count exceeded threshold\r\n");
+ gRunFlag = FALSE;
+ continue;
+ }
+ }
+
+ /* Wait for Tx interrupt with timeout */
+ status = SemaphoreP_pend(&gPruI2s0TxSemObj, SEMAPHORE_TIMEOUT_MS);
+ if (status != SystemP_SUCCESS)
+ {
+ DebugP_log("ERROR: Timeout waiting for PRU I2S0 Tx event\r\n");
+ gRunFlag = FALSE;
+ continue;
+ }
+
+ gLoopCnt++;
+
+ /* Display periodic progress (every 1000 iterations) */
+ if ((gLoopCnt % 1000) == 0)
+ {
+ DebugP_log("Tx streaming: %d iterations completed\r", gLoopCnt);
+ }
+
+ /* Update Tx buffer pointer with wraparound */
+ gPruI2s0TxCnt += gPruI2s0XferSz;
+ gPPruI2s0TxBuf += gPruI2s0XferSz;
+ if (gPruI2s0TxCnt >= TX_BUF_SZ_32B)
+ {
+ gPPruI2s0TxBuf = &gPruI2s0TxBuf[0];
+ gPruI2s0TxCnt = 0;
+ }
+ }
+
+ DebugP_log("\r\nTx streaming loop terminated after %d iterations\r\n", gLoopCnt);
+}
+
+/**
+ * \brief Real-time audio streaming loop (Rx-only mode)
+ *
+ * \param hRx Handle to PRU I2S Rx instance
+ *
+ * \details Rx-only streaming loop for half-duplex receive operation that:
+ * - Waits for Rx interrupt via semaphore
+ * - Reads Rx buffers
+ * - Updates buffer pointers with wraparound
+ * - Displays periodic progress
+ * - Monitors error conditions
+ */
+static void prui2s_streaming_loop_rx_only(PRUI2S_Handle hRx)
+{
+ PRUI2S_IoBuf rdIoBuf;
+ int32_t status;
+
+ gLoopCnt = 0;
+ gRunFlag = TRUE;
+
+ DebugP_log("\r\nStarting real-time audio streaming loop (RX-ONLY mode)...\r\n");
+ DebugP_log("Press Ctrl+C to stop\r\n\r\n");
+
+ while (gRunFlag == TRUE)
+ {
+ /* Wait for Rx interrupt with timeout */
+ status = SemaphoreP_pend(&gPruI2s1RxSemObj, SEMAPHORE_TIMEOUT_MS);
+ if (status != SystemP_SUCCESS)
+ {
+ DebugP_log("ERROR: Timeout waiting for PRU I2S1 Rx event\r\n");
+ gRunFlag = FALSE;
+ continue;
+ }
+
+ gLoopCnt++;
+
+ /* Read next PRU I2S1 Rx ping/pong buffer */
+ PRUI2S_ioBufInit(&rdIoBuf);
+ rdIoBuf.ioBufAddr = gPPruI2s1RxBuf;
+ status = PRUI2S_read(hRx, &rdIoBuf);
+ if (status != PRUI2S_DRV_SOK)
+ {
+ gPruI2s1RdErrCnt++;
+ if (gPruI2s1RdErrCnt == 1 || (gPruI2s1RdErrCnt % ERROR_LOG_INTERVAL) == 0)
+ {
+ DebugP_log("ERROR: PRU I2S1 read error (count: %d)\r\n", gPruI2s1RdErrCnt);
+ }
+ if (gPruI2s1RdErrCnt > ERROR_COUNT_THRESHOLD)
+ {
+ DebugP_log("ERROR: PRU I2S1 read error count exceeded threshold\r\n");
+ gRunFlag = FALSE;
+ continue;
+ }
+ }
+
+ /* Display periodic progress (every 1000 iterations) */
+ if ((gLoopCnt % 1000) == 0)
+ {
+ DebugP_log("Rx streaming: %d iterations completed\r", gLoopCnt);
+ }
+
+ /* Update Rx buffer pointer with wraparound */
+ gPruI2s1RxCnt += gPruI2s1XferSz;
+ gPPruI2s1RxBuf += gPruI2s1XferSz;
+ if (gPruI2s1RxCnt >= RX_BUF_SZ_32B)
+ {
+ gPPruI2s1RxBuf = &gPruI2s1RxBuf[0];
+ gPruI2s1RxCnt = 0;
+ }
+ }
+
+ DebugP_log("\r\nRx streaming loop terminated after %d iterations\r\n", gLoopCnt);
+}
+
+/**
+ * \brief Display accumulated error and performance statistics
+ */
+static void prui2s_display_statistics(void)
+{
+ uint32_t totalErrors = 0;
+
+ DebugP_log("\r\n========================================\r\n");
+ DebugP_log("PRU I2S Diagnostic Statistics\r\n");
+ DebugP_log("========================================\r\n");
+
+ DebugP_log("\r\nPRU I2S 0 (Tx):\r\n");
+ DebugP_log(" Tx ISR Count: %d\r\n", gPruI2s0TxIsrCnt);
+ DebugP_log(" Tx Write Errors: %d\r\n", gPruI2s0WrtErrCnt);
+ DebugP_log(" Clear Tx Int Errors: %d\r\n", gPruI2s0ClrTxIntErrCnt);
+ DebugP_log(" Error ISR Count: %d\r\n", gPruI2s0ErrIsrCnt);
+ DebugP_log(" Overflow Errors: %d\r\n", gPruI2s0ErrOvrCnt);
+ DebugP_log(" Underflow Errors: %d\r\n", gPruI2s0ErrUndCnt);
+ DebugP_log(" Frame Sync Errors: %d\r\n", gPruI2s0ErrFsyncCnt);
+
+ totalErrors += gPruI2s0WrtErrCnt + gPruI2s0ClrTxIntErrCnt + gPruI2s0ErrOvrCnt +
+ gPruI2s0ErrUndCnt + gPruI2s0ErrFsyncCnt;
+
+ DebugP_log("\r\nPRU I2S 1 (Rx):\r\n");
+ DebugP_log(" Rx ISR Count: %d\r\n", gPruI2s1RxIsrCnt);
+ DebugP_log(" Rx Read Errors: %d\r\n", gPruI2s1RdErrCnt);
+ DebugP_log(" Clear Rx Int Errors: %d\r\n", gPruI2s1ClrRxIntErrCnt);
+ DebugP_log(" Error ISR Count: %d\r\n", gPruI2s1ErrIsrCnt);
+ DebugP_log(" Overflow Errors: %d\r\n", gPruI2s1ErrOvrCnt);
+ DebugP_log(" Underflow Errors: %d\r\n", gPruI2s1ErrUndCnt);
+ DebugP_log(" Frame Sync Errors: %d\r\n", gPruI2s1ErrFsyncCnt);
+
+ totalErrors += gPruI2s1RdErrCnt + gPruI2s1ClrRxIntErrCnt + gPruI2s1ErrOvrCnt +
+ gPruI2s1ErrUndCnt + gPruI2s1ErrFsyncCnt;
+
+ DebugP_log("\r\nTotal Loop Iterations: %d\r\n", gLoopCnt);
+ DebugP_log("Total Errors: %d\r\n", totalErrors);
+ DebugP_log("========================================\r\n");
+}
+
+/**
+ * \brief Display PRU I2S configuration information
+ */
+static void prui2s_display_configuration(void)
+{
+ PRUI2S_SwipAttrs attrs0, attrs1;
+ int32_t status;
+
+ DebugP_log("\r\n========================================\r\n");
+ DebugP_log("PRU I2S Configuration\r\n");
+ DebugP_log("========================================\r\n");
+
+ /* Get configuration for instance 0 */
+ status = PRUI2S_getInitCfg(TEST_PRUI2S0_IDX, &attrs0);
+ if(status == PRUI2S_DRV_SOK)
+ {
+ DebugP_log("\r\nPRU I2S 0 (Tx):\r\n");
+ DebugP_log(" Tx Channels: %d\r\n", attrs0.numTxI2s);
+ DebugP_log(" Rx Channels: %d\r\n", attrs0.numRxI2s);
+ DebugP_log(" Sampling Rate: %d kHz\r\n", attrs0.sampFreq);
+ DebugP_log(" Bits Per Slot: %d\r\n", attrs0.bitsPerSlot);
+ DebugP_log(" Buffer Size: %d bytes\r\n", PRUI2S0_TX_PING_PONG_BUF_SZ);
+ }
+
+ /* Get configuration for instance 1 */
+ status = PRUI2S_getInitCfg(TEST_PRUI2S1_IDX, &attrs1);
+ if(status == PRUI2S_DRV_SOK)
+ {
+ DebugP_log("\r\nPRU I2S 1 (Rx):\r\n");
+ DebugP_log(" Tx Channels: %d\r\n", attrs1.numTxI2s);
+ DebugP_log(" Rx Channels: %d\r\n", attrs1.numRxI2s);
+ DebugP_log(" Sampling Rate: %d kHz\r\n", attrs1.sampFreq);
+ DebugP_log(" Bits Per Slot: %d\r\n", attrs1.bitsPerSlot);
+ DebugP_log(" Buffer Size: %d bytes\r\n", PRUI2S1_RX_PING_PONG_BUF_SZ);
+ }
+
+ DebugP_log("\r\n========================================\r\n");
+}
+
+/**
+ * \brief Cleanup semaphores
+ */
+static void prui2s_cleanup_semaphores(void)
+{
+ if(gSemaphoresInitialized)
+ {
+ SemaphoreP_destruct(&gPruI2s0TxSemObj);
+ SemaphoreP_destruct(&gPruI2s1RxSemObj);
+ gSemaphoresInitialized = FALSE;
+ DebugP_log("Semaphores destroyed\r\n");
+ }
+}
+
+/**
+ * \brief Cleanup PRU I2S instances
+ */
+static void prui2s_cleanup_instances(void)
+{
+ int32_t status;
+
+ /* Close PRU I2S 0 instance */
+ if(gHPruI2s0 != NULL)
+ {
+ status = PRUI2S_close(gHPruI2s0);
+ if (status != PRUI2S_DRV_SOK)
+ {
+ DebugP_log("ERROR: PRUI2S_close() PRU I2S 0 failed\r\n");
+ }
+ else
+ {
+ DebugP_log("PRU I2S 0 closed successfully\r\n");
+ }
+ gHPruI2s0 = NULL;
+ }
+
+ /* Close PRU I2S 1 instance */
+ if(gHPruI2s1 != NULL)
+ {
+ status = PRUI2S_close(gHPruI2s1);
+ if (status != PRUI2S_DRV_SOK)
+ {
+ DebugP_log("ERROR: PRUI2S_close() PRU I2S 1 failed\r\n");
+ }
+ else
+ {
+ DebugP_log("PRU I2S 1 closed successfully\r\n");
+ }
+ gHPruI2s1 = NULL;
+ }
+
+ /* Deinitialize PRU I2S driver */
+ PRUI2S_deinit();
+ DebugP_log("PRU I2S driver deinitialized\r\n");
+}
+
+/* ========================================================================== */
+/* ISR Handler Definitions */
+/* ========================================================================== */
+
+/**
+ * \brief PRU I2S 0 Tx interrupt handler
+ *
+ * \param args PRU I2S handle (passed from driver)
+ */
+void pruI2s0TxIrqHandler(void *args)
+{
+ PRUI2S_Handle handle = (PRUI2S_Handle)args;
+ int32_t status;
+
+ /* Increment ISR count for statistics */
+ gPruI2s0TxIsrCnt++;
+
+ /* Clear PRU I2S Tx interrupt */
+ status = PRUI2S_clearInt(handle, INTR_TYPE_I2S_TX);
+ if (status != PRUI2S_DRV_SOK)
+ {
+ gPruI2s0ClrTxIntErrCnt++;
+ }
+
+ /* Signal semaphore to unblock main task */
+ SemaphoreP_post(&gPruI2s0TxSemObj);
+}
+
+/**
+ * \brief PRU I2S 0 error interrupt handler
+ *
+ * \param args PRU I2S handle (passed from driver)
+ */
+void pruI2s0ErrIrqHandler(void *args)
+{
+ PRUI2S_Handle handle = (PRUI2S_Handle)args;
+ uint8_t errStat;
+ int32_t status;
+
+ /* Increment error ISR count for statistics */
+ gPruI2s0ErrIsrCnt++;
+
+ /* Clear PRU I2S error interrupt */
+ status = PRUI2S_clearInt(handle, INTR_TYPE_I2S_ERR);
+ if (status != PRUI2S_DRV_SOK)
+ {
+ gPruI2s0ClrErrIntErrCnt++;
+ if (gPruI2s0ClrErrIntErrCnt == 1 || (gPruI2s0ClrErrIntErrCnt % ERROR_LOG_INTERVAL) == 0)
+ {
+ DebugP_log("ERROR: Failed to clear PRU I2S0 error interrupt (count: %d)\r\n",
+ gPruI2s0ClrErrIntErrCnt);
+ }
+ }
+
+ /* Get error status register */
+ PRUI2S_getErrStat(handle, &errStat);
+
+ /* Check for Rx overflow error */
+ if (errStat & ERROR_BIT_POSITION(I2S_ERR_OVR_BN))
+ {
+ gPruI2s0ErrOvrCnt++;
+ if (gPruI2s0ErrOvrCnt == 1 || (gPruI2s0ErrOvrCnt % ERROR_LOG_INTERVAL) == 0)
+ {
+ DebugP_log("ERROR: PRU I2S0 Rx overflow error (count: %d)\r\n", gPruI2s0ErrOvrCnt);
+ }
+ }
+
+ /* Check for Tx underflow error */
+ if (errStat & ERROR_BIT_POSITION(I2S_ERR_UND_BN))
+ {
+ gPruI2s0ErrUndCnt++;
+ if (gPruI2s0ErrUndCnt == 1 || (gPruI2s0ErrUndCnt % ERROR_LOG_INTERVAL) == 0)
+ {
+ DebugP_log("ERROR: PRU I2S0 Tx underflow error (count: %d)\r\n", gPruI2s0ErrUndCnt);
+ }
+ }
+
+ /* Check for frame sync error */
+ if (errStat & ERROR_BIT_POSITION(I2S_ERR_FSYNC_BN))
+ {
+ gPruI2s0ErrFsyncCnt++;
+ if (gPruI2s0ErrFsyncCnt == 1 || (gPruI2s0ErrFsyncCnt % ERROR_LOG_INTERVAL) == 0)
+ {
+ DebugP_log("ERROR: PRU I2S0 frame sync error (count: %d)\r\n", gPruI2s0ErrFsyncCnt);
+ }
+ }
+
+ /* Clear error status register */
+ PRUI2S_clearErrStat(handle, errStat);
+}
+
+/**
+ * \brief PRU I2S 1 Rx interrupt handler
+ *
+ * \param args PRU I2S handle (passed from driver)
+ */
+void pruI2s1RxIrqHandler(void *args)
+{
+ PRUI2S_Handle handle = (PRUI2S_Handle)args;
+ int32_t status;
+
+ /* Increment ISR count for statistics */
+ gPruI2s1RxIsrCnt++;
+
+ /* Clear PRU I2S Rx interrupt */
+ status = PRUI2S_clearInt(handle, INTR_TYPE_I2S_RX);
+ if (status != PRUI2S_DRV_SOK)
+ {
+ gPruI2s1ClrRxIntErrCnt++;
+ }
+
+ /* Signal semaphore to unblock main task */
+ SemaphoreP_post(&gPruI2s1RxSemObj);
+}
+
+/**
+ * \brief PRU I2S 1 error interrupt handler
+ *
+ * \param args PRU I2S handle (passed from driver)
+ */
+void pruI2s1ErrIrqHandler(void *args)
+{
+ PRUI2S_Handle handle = (PRUI2S_Handle)args;
+ uint8_t errStat;
+ int32_t status;
+
+ /* Increment error ISR count for statistics */
+ gPruI2s1ErrIsrCnt++;
+
+ /* Clear PRU I2S error interrupt */
+ status = PRUI2S_clearInt(handle, INTR_TYPE_I2S_ERR);
+ if (status != PRUI2S_DRV_SOK)
+ {
+ gPruI2s1ClrErrIntErrCnt++;
+ if (gPruI2s1ClrErrIntErrCnt == 1 || (gPruI2s1ClrErrIntErrCnt % ERROR_LOG_INTERVAL) == 0)
+ {
+ DebugP_log("ERROR: Failed to clear PRU I2S1 error interrupt (count: %d)\r\n",
+ gPruI2s1ClrErrIntErrCnt);
+ }
+ }
+
+ /* Get error status register */
+ PRUI2S_getErrStat(handle, &errStat);
+
+ /* Check for Rx overflow error */
+ if (errStat & ERROR_BIT_POSITION(I2S_ERR_OVR_BN))
+ {
+ gPruI2s1ErrOvrCnt++;
+ if (gPruI2s1ErrOvrCnt == 1 || (gPruI2s1ErrOvrCnt % ERROR_LOG_INTERVAL) == 0)
+ {
+ DebugP_log("ERROR: PRU I2S1 Rx overflow error (count: %d)\r\n", gPruI2s1ErrOvrCnt);
+ }
+ }
+
+ /* Check for Tx underflow error */
+ if (errStat & ERROR_BIT_POSITION(I2S_ERR_UND_BN))
+ {
+ gPruI2s1ErrUndCnt++;
+ if (gPruI2s1ErrUndCnt == 1 || (gPruI2s1ErrUndCnt % ERROR_LOG_INTERVAL) == 0)
+ {
+ DebugP_log("ERROR: PRU I2S1 Tx underflow error (count: %d)\r\n", gPruI2s1ErrUndCnt);
+ }
+ }
+
+ /* Check for frame sync error */
+ if (errStat & ERROR_BIT_POSITION(I2S_ERR_FSYNC_BN))
+ {
+ gPruI2s1ErrFsyncCnt++;
+ if (gPruI2s1ErrFsyncCnt == 1 || (gPruI2s1ErrFsyncCnt % ERROR_LOG_INTERVAL) == 0)
+ {
+ DebugP_log("ERROR: PRU I2S1 frame sync error (count: %d)\r\n", gPruI2s1ErrFsyncCnt);
+ }
+ }
+
+ /* Clear error status register */
+ PRUI2S_clearErrStat(handle, errStat);
+}
+
+/**
+ * \brief PRU I2S diagnostic main entry point
+ *
+ * \param args Unused
+ */
+
+/* ========================================================================== */
+/* Main Function */
+/* ========================================================================== */
+
+/**
+ * \brief Main diagnostic application entry point
+ *
+ * \param args Unused
+ *
+ * \details Application initialization and execution flow:
+ * STEP 1: Initialize system drivers
+ * STEP 2: Initialize PRU-ICSS subsystem
+ * STEP 3: Initialize semaphores
+ * STEP 4: Initialize PRU I2S driver
+ * STEP 5: Load and run PRU firmware
+ * STEP 6: Execute streaming loop (full/half-duplex)
+ * STEP 7: Display statistics
+ * STEP 8: Cleanup and shutdown
+ */
+void pru_i2s_diagnostic_main(void *args)
+{
+ int32_t status = SystemP_SUCCESS;
+ uint8_t numValidCfg;
+
+ /* ========================================================================== */
+ /* STEP 1: Initialize system drivers and board peripherals */
+ /* ========================================================================== */
+ Drivers_open();
+ Board_driversOpen();
+
+ DebugP_log("\r\n========================================\r\n");
+ DebugP_log("PRU I2S Diagnostic Application\r\n");
+ DebugP_log("========================================\r\n");
+ DebugP_log("Build timestamp: %s %s\r\n", __DATE__, __TIME__);
+ DebugP_log("Mode: %s\r\n", (CONFIG_I2S0_MODE == TDM_MODE) ? "TDM" : "I2S");
+
+ /* ========================================================================== */
+ /* STEP 2: Initialize PRU-ICSS subsystem */
+ /* ========================================================================== */
+ prui2s_pruicss_init();
+
+#ifdef SOC_AM263X
+ /* ========================================================================== */
+ /* STEP 2a: Configure board IO expander for signal routing */
+ /* ========================================================================== */
+ prui2s_board_io_expander_init();
+#endif
+
+ /* ========================================================================== */
+ /* STEP 3: Initialize semaphores for ISR-to-task synchronization */
+ /* ========================================================================== */
+ status = prui2s_init_semaphores();
+ if(status != SystemP_SUCCESS)
+ {
+ goto cleanup;
+ }
+
+ /* ========================================================================== */
+ /* STEP 4: Initialize PRU I2S driver */
+ /* ========================================================================== */
+
+ /* Apply application-specific configuration */
+ extern int32_t PRUI2S_applyAppConfig(void);
+ status = PRUI2S_applyAppConfig();
+ if (status != PRUI2S_DRV_SOK)
+ {
+ DebugP_log("ERROR: PRUI2S_applyAppConfig() failed\r\n");
+ goto cleanup;
+ }
+
+ /* INTC initialization already done via PRUICSS_intcInit() earlier */
+
+ /* Initialize PRU I2S driver (loads configuration, validates instances) */
+ status = PRUI2S_init(&numValidCfg, &gPruFwImageInfo);
+ if (status == PRUI2S_DRV_SERR_INIT_FWIMG)
+ {
+ DebugP_log("WARNING: PRUI2S_init() no FW image for configuration\r\n");
+ }
+ else if (status != PRUI2S_DRV_SOK)
+ {
+ DebugP_log("ERROR: PRUI2S_init() failed with status: %d\r\n", status);
+ if (status == PRUI2S_DRV_SERR_INIT)
+ {
+ DebugP_log(" Likely cause: SemaphoreP_constructMutex() failed during driver init\r\n");
+ DebugP_log(" This typically indicates RTOS resource exhaustion or init called multiple times\r\n");
+ }
+ goto cleanup;
+ }
+
+ DebugP_log("PRU I2S driver initialized (%d valid configurations)\r\n", numValidCfg);
+
+ /* Validate test configuration indices */
+ if (((numValidCfg-1) < TEST_PRUI2S0_IDX) || ((numValidCfg-1) < TEST_PRUI2S1_IDX))
+ {
+ DebugP_log("ERROR: Invalid test configuration indices\r\n");
+ goto cleanup;
+ }
+
+ /* Initialize PRU I2S instances (conditional based on SysConfig) */
+#if defined(CONFIG_PRU_I2S0_ENABLED) && (CONFIG_PRU_I2S0_ENABLED == 1)
+ /* Initialize PRU I2S 0 (Tx) instance */
+ status = prui2s_init_instance(TEST_PRUI2S0_IDX, &gHPruI2s0);
+ if(status != SystemP_SUCCESS)
+ {
+ goto cleanup;
+ }
+#endif
+
+#if defined(CONFIG_PRU_I2S1_ENABLED) && (CONFIG_PRU_I2S1_ENABLED == 1)
+ /* Initialize PRU I2S 1 (Rx) instance */
+ status = prui2s_init_instance(TEST_PRUI2S1_IDX, &gHPruI2s1);
+ if(status != SystemP_SUCCESS)
+ {
+ goto cleanup;
+ }
+#endif
+
+ /* ========================================================================== */
+ /* STEP 5: Load firmware and enable PRU cores */
+ /* ========================================================================== */
+
+ /* Load and run firmware on PRU cores */
+ prui2s_pruicss_load_run_fw();
+
+ /* Display firmware versions for enabled instances */
+#if defined(CONFIG_PRU_I2S0_ENABLED) && (CONFIG_PRU_I2S0_ENABLED == 1)
+ prui2s_display_fw_version(PRUICSS_PRU0);
+#endif
+#if defined(CONFIG_PRU_I2S1_ENABLED) && (CONFIG_PRU_I2S1_ENABLED == 1)
+ prui2s_display_fw_version(PRUICSS_PRU1);
+#endif
+
+ /* Enable PRU I2S instances (conditional based on SysConfig) */
+#if defined(CONFIG_PRU_I2S0_ENABLED) && (CONFIG_PRU_I2S0_ENABLED == 1)
+ status = PRUI2S_enable(gHPruI2s0);
+ if (status != PRUI2S_DRV_SOK)
+ {
+ DebugP_log("ERROR: PRUI2S_enable() PRU I2S 0 failed\r\n");
+ goto cleanup;
+ }
+#endif
+
+#if defined(CONFIG_PRU_I2S1_ENABLED) && (CONFIG_PRU_I2S1_ENABLED == 1)
+ status = PRUI2S_enable(gHPruI2s1);
+ if (status != PRUI2S_DRV_SOK)
+ {
+ DebugP_log("ERROR: PRUI2S_enable() PRU I2S 1 failed\r\n");
+ goto cleanup;
+ }
+#endif
+
+ DebugP_log("\r\nAll PRU I2S instances enabled and ready\r\n");
+
+ /* Display configuration information */
+ prui2s_display_configuration();
+
+ /* ========================================================================== */
+ /* STEP 6: Real-time audio streaming loop */
+ /* ========================================================================== */
+#if defined(CONFIG_PRU_I2S0_ENABLED) && (CONFIG_PRU_I2S0_ENABLED == 1) && \
+ defined(CONFIG_PRU_I2S1_ENABLED) && (CONFIG_PRU_I2S1_ENABLED == 1)
+ /* Full-duplex mode: Both Tx (PRU0) and Rx (PRU1) enabled */
+ prui2s_streaming_loop_full_duplex(gHPruI2s0, gHPruI2s1);
+#elif defined(CONFIG_PRU_I2S0_ENABLED) && (CONFIG_PRU_I2S0_ENABLED == 1)
+ /* Half-duplex Tx-only mode: Only PRU0 (Tx) enabled */
+ prui2s_streaming_loop_tx_only(gHPruI2s0);
+#elif defined(CONFIG_PRU_I2S1_ENABLED) && (CONFIG_PRU_I2S1_ENABLED == 1)
+ /* Half-duplex Rx-only mode: Only PRU1 (Rx) enabled */
+ prui2s_streaming_loop_rx_only(gHPruI2s1);
+#else
+ /* No instances enabled - skip streaming */
+ DebugP_log("\r\nWARNING: No PRU I2S instances enabled. Skipping streaming loop.\r\n");
+#endif
+
+ /* ========================================================================== */
+ /* STEP 7: Display statistics */
+ /* ========================================================================== */
+ prui2s_display_statistics();
+cleanup:
+ /* ========================================================================== */
+ /* STEP 8: Cleanup and shutdown */
+ /* ========================================================================== */
+
+ prui2s_cleanup_instances();
+ prui2s_cleanup_semaphores();
+
+ DebugP_log("\r\nAll tests have passed!\r\n");
+
+ Board_driversClose();
+ Drivers_close();
+}
diff --git a/source/.meta/pru_i2s/pru_i2s.syscfg.js b/source/.meta/pru_i2s/pru_i2s.syscfg.js
new file mode 100644
index 000000000..3002996f9
--- /dev/null
+++ b/source/.meta/pru_i2s/pru_i2s.syscfg.js
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2024-2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * distribution and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+let common = system.getScript("/common");
+let pru_i2s_module_name = "/pru_i2s/pru_i2s";
+let device = common.getDeviceName();
+let is_am26x_soc = (device === "am263x-cc" || device === "am261x-lp" || device === "am263px-cc") ? true : false;
+let is_am263x_soc = (device === "am263x-cc") ? true : false;
+let is_am261x_soc = (device === "am261x-lp") ? true : false;
+let is_am263px_soc = (device === "am263px-cc") ? true : false;
+
+function onValidate(inst, validation) {
+ /* Validate that at least one channel (Tx or Rx) is enabled */
+ if (inst.Num_Tx_Channels === 0 && inst.Num_Rx_Channels === 0) {
+ validation.logError("At least one Tx or Rx channel must be enabled", inst, "Num_Tx_Channels");
+ }
+
+ /* Validate channel limits */
+ if (inst.Num_Tx_Channels > 3) {
+ validation.logError("Maximum 3 Tx channels supported", inst, "Num_Tx_Channels");
+ }
+
+ if (inst.Num_Rx_Channels > 2) {
+ validation.logError("Maximum 2 Rx channels supported", inst, "Num_Rx_Channels");
+ }
+
+ /* Validate TDM mode requirements */
+ if (inst.Mode === "TDM") {
+ let total_channels = inst.Num_Tx_Channels + inst.Num_Rx_Channels;
+ if (total_channels > 4) {
+ validation.logWarning(
+ "TDM mode with " + total_channels + " channels may require special firmware configuration",
+ inst,
+ "Mode"
+ );
+ }
+ }
+
+ /* Validate sampling frequency for high channel counts */
+ if ((inst.Num_Tx_Channels + inst.Num_Rx_Channels) > 2 &&
+ parseInt(inst.Sampling_Freq) > 48) {
+ validation.logWarning(
+ "Sampling frequencies above 48 kHz with multiple channels may have performance limitations",
+ inst,
+ "Sampling_Freq"
+ );
+ }
+}
+
+let pru_i2s_module = {
+ displayName: "PRU I2S Audio Interface",
+ templates: {
+ "/drivers/system/system_config.c.xdt": {
+ driver_config: "/pru_i2s/pru_i2s_templates.c.xdt",
+ moduleName: pru_i2s_module_name,
+ },
+ "/drivers/system/system_config.h.xdt": {
+ driver_config: "/pru_i2s/pru_i2s_templates.h.xdt",
+ moduleName: pru_i2s_module_name,
+ },
+ "/drivers/pinmux/pinmux_config.c.xdt": {
+ moduleName: pru_i2s_module_name,
+ },
+ },
+ defaultInstanceName: "CONFIG_PRU_I2S",
+ config: [
+ {
+ name: "instance",
+ displayName: "ICSS Instance",
+ description: "Select the ICSS (Industrial Communication SubSystem) instance",
+ default: (is_am261x_soc) ? "ICSSM1" : "ICSSM0",
+ options: (is_am261x_soc) ?
+ [
+ {
+ name: "ICSSM0",
+ displayName: "ICSSM0"
+ },
+ {
+ name: "ICSSM1",
+ displayName: "ICSSM1"
+ }
+ ]
+ :
+ (is_am263x_soc || is_am263px_soc) ?
+ [
+ {
+ name: "ICSSM",
+ displayName: "ICSSM0"
+ }
+ ]
+ :
+ [
+ {
+ name: "ICSSG0",
+ },
+ {
+ name: "ICSSG1",
+ }
+ ]
+ },
+ {
+ name: "PRU_Slice",
+ displayName: "PRU Core",
+ description: "Select PRU core (slice) for I2S operation",
+ default: "PRU0",
+ options: [
+ {
+ name: "PRU0",
+ displayName: "PRU0"
+ },
+ {
+ name: "PRU1",
+ displayName: "PRU1"
+ },
+ ],
+ },
+ {
+ name: "Mode",
+ displayName: "I2S/TDM Mode",
+ description: "Select I2S (standard stereo) or TDM (multi-channel time division multiplexing) mode",
+ longDescription: `
+**I2S Mode**: Standard Inter-IC Sound protocol for stereo audio
+- Typically 2 channels (left/right)
+- Standard for audio codecs and DACs
+- Lower latency
+
+**TDM Mode**: Time Division Multiplexing for multi-channel audio
+- Supports up to 4+ channels
+- Used in multi-microphone arrays and multi-speaker systems
+- Higher throughput
+ `,
+ default: "I2S",
+ options: [
+ {
+ name: "I2S",
+ displayName: "I2S Mode (Standard Stereo)"
+ },
+ {
+ name: "TDM",
+ displayName: "TDM Mode (Multi-Channel)"
+ },
+ ],
+ },
+ {
+ name: "Num_Tx_Channels",
+ displayName: "Number of Tx Channels",
+ description: "Number of transmit (output) I2S channels (0-3)",
+ longDescription: `
+Specify the number of I2S transmit channels:
+- **0**: No transmit channels (Rx only configuration)
+- **1**: Single Tx channel (mono or single stereo pair)
+- **2**: Two Tx channels (dual stereo pairs)
+- **3**: Three Tx channels (6 audio channels in TDM)
+
+Common configurations:
+- Tx=1, Rx=0: Audio output only (DAC)
+- Tx=0, Rx=1: Audio input only (ADC/microphone)
+- Tx=1, Rx=1: Full-duplex audio (codec)
+ `,
+ default: 1,
+ options: [
+ { name: 0, displayName: "0 (Rx only)" },
+ { name: 1, displayName: "1" },
+ { name: 2, displayName: "2" },
+ { name: 3, displayName: "3 (TDM)" },
+ ],
+ },
+ {
+ name: "Num_Rx_Channels",
+ displayName: "Number of Rx Channels",
+ description: "Number of receive (input) I2S channels (0-2)",
+ longDescription: `
+Specify the number of I2S receive channels:
+- **0**: No receive channels (Tx only configuration)
+- **1**: Single Rx channel (mono or single stereo pair)
+- **2**: Two Rx channels (dual stereo pairs / 4-mic array)
+
+Common configurations:
+- Tx=1, Rx=0: Audio output only (DAC)
+- Tx=0, Rx=1: Audio input only (ADC/microphone)
+- Tx=1, Rx=1: Full-duplex audio (codec)
+- Tx=0, Rx=2: Stereo microphone array
+ `,
+ default: 0,
+ options: [
+ { name: 0, displayName: "0 (Tx only)" },
+ { name: 1, displayName: "1" },
+ { name: 2, displayName: "2 (Multi-mic)" },
+ ],
+ },
+ {
+ name: "Sampling_Freq",
+ displayName: "Sampling Frequency",
+ description: "Audio sampling frequency in kHz",
+ longDescription: `
+Select the audio sampling frequency:
+- **8 kHz**: Voice/telephony applications
+- **16 kHz**: Wideband voice, basic audio
+- **32 kHz**: Digital radio, some audio applications
+- **48 kHz**: Professional audio, CD quality
+- **96 kHz**: High-resolution audio
+
+Note: Higher sampling frequencies require more PRU processing power and memory bandwidth.
+ `,
+ default: "48",
+ options: [
+ { name: "8", displayName: "8 kHz (Voice)" },
+ { name: "16", displayName: "16 kHz (Wideband Voice)" },
+ { name: "32", displayName: "32 kHz (Digital Radio)" },
+ { name: "48", displayName: "48 kHz (CD Quality)" },
+ { name: "96", displayName: "96 kHz (High-Res Audio)" },
+ ],
+ },
+ {
+ name: "Bits_Per_Slot",
+ displayName: "Bits Per Slot",
+ description: "Number of bits per I2S time slot",
+ longDescription: `
+Select the bit depth per I2S time slot:
+- **16 bits**: Basic audio quality, lower bandwidth
+- **24 bits**: Professional audio quality
+- **32 bits**: Maximum audio quality, highest bandwidth
+
+Note: Actual audio resolution depends on the codec/ADC/DAC capabilities.
+The I2S interface uses this value for framing and timing.
+ `,
+ default: "32",
+ options: [
+ { name: "16", displayName: "16 bits" },
+ { name: "24", displayName: "24 bits" },
+ { name: "32", displayName: "32 bits" },
+ ],
+ },
+ {
+ name: "INTC_Config",
+ displayName: "INTC Configuration",
+ description: "PRU-ICSS interrupt controller event configuration",
+ config: [
+ {
+ name: "Tx_INTC_Event",
+ displayName: "Tx System Event",
+ description: "INTC system event number for Tx complete interrupt",
+ default: 18,
+ },
+ {
+ name: "Rx_INTC_Event",
+ displayName: "Rx System Event",
+ description: "INTC system event number for Rx complete interrupt",
+ default: 19,
+ },
+ {
+ name: "Err_INTC_Event",
+ displayName: "Error System Event",
+ description: "INTC system event number for error interrupt (overflow/underflow)",
+ default: 20,
+ },
+ ],
+ },
+ {
+ name: "Clock_Config",
+ displayName: "Clock Configuration",
+ description: "PRU core and peripheral clock settings",
+ config: [
+ {
+ name: "Core_Clk_Freq",
+ displayName: "PRU Core Clock (Hz)",
+ description: "PRU core clock frequency in Hz",
+ default: 200000000, /* 200 MHz typical */
+ },
+ ],
+ },
+ ],
+ validate: onValidate,
+ moduleStatic: {
+ modules: function(inst) {
+ let modArray = [];
+
+ /* Add PRUICSS dependency */
+ modArray.push({
+ name: "pruicss",
+ moduleName: "/drivers/pruicss/pruicss",
+ });
+
+ return modArray;
+ },
+ },
+};
+
+exports = pru_i2s_module;
diff --git a/source/.meta/pru_i2s/pru_i2s_config.c.xdt b/source/.meta/pru_i2s/pru_i2s_config.c.xdt
new file mode 100644
index 000000000..c2774c9c3
--- /dev/null
+++ b/source/.meta/pru_i2s/pru_i2s_config.c.xdt
@@ -0,0 +1,114 @@
+%%{
+/*
+ * Copyright (C) 2024-2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Auto generated file - DO NOT MODIFY if you want to regenerate from SysConfig
+ * If you want custom configuration, you can edit this file manually after generation
+ */
+
+ let module = system.modules["/drivers/pruicss/pruicss"];
+ let common = system.getScript("/common");
+ let soc = system.getScript(`/drivers/soc/drivers_${common.getSocName()}`);
+%%}
+
+#include
+#include
+#include
+
+/* PRU I2S SWIP attributes - Generated from SysConfig */
+PRUI2S_SwipAttrs gPruI2sSwipAttrs[PRU_I2S_MAX_NUM_INST] =
+{
+% if (module) {
+% for(let i = 0; i < module.$instances.length; i++) {
+% let instance = module.$instances[i];
+% let config = module.getInstanceConfig(instance);
+% let icssNum = 0;
+% if (instance.instance == "ICSSG0" || instance.instance == "ICSSM" || instance.instance == "ICSSM0") {
+% icssNum = 0;
+% } else {
+% icssNum = 1;
+% }
+ /* Configuration `i` - `instance.$name` */
+ {
+ .baseAddr = 0, /* Set by driver based on ICSS instance and PRU core */
+ .icssInstId = `icssNum`, /* ICSS instance from SysConfig */
+ .pruInstId = PRUICSS_PRU0, /* PRU core - modify as needed (PRUICSS_PRU0 or PRUICSS_PRU1) */
+ .numTxI2s = 0, /* Detected from firmware at runtime */
+ .numRxI2s = 0, /* Detected from firmware at runtime */
+ .sampFreq = 0, /* Detected from firmware at runtime */
+ .bitsPerSlot = 0, /* Detected from firmware at runtime */
+ .i2sTxHostIntNum = 0, /* Detected from firmware at runtime */
+ .i2sRxHostIntNum = 0, /* Detected from firmware at runtime */
+ .i2sErrHostIntNum = 0, /* Detected from firmware at runtime */
+ .i2sTxIcssIntcSysEvt = 0, /* Detected from firmware at runtime */
+ .i2sRxIcssIntcSysEvt = 0, /* Detected from firmware at runtime */
+ .i2sErrIcssIntcSysEvt = 0, /* Detected from firmware at runtime */
+ .intcInitData = NULL, /* Set by application via PRUI2S_setIntcInitData() */
+ },
+% }
+% } else {
+ /* Default configuration - No PRUICSS instance configured in SysConfig */
+ {
+ .baseAddr = 0,
+ .icssInstId = 0,
+ .pruInstId = PRUICSS_PRU0,
+ .numTxI2s = 0,
+ .numRxI2s = 0,
+ .sampFreq = 0,
+ .bitsPerSlot = 0,
+ .i2sTxHostIntNum = 0,
+ .i2sRxHostIntNum = 0,
+ .i2sErrHostIntNum = 0,
+ .i2sTxIcssIntcSysEvt = 0,
+ .i2sRxIcssIntcSysEvt = 0,
+ .i2sErrIcssIntcSysEvt = 0,
+ .intcInitData = NULL,
+ },
+ {
+ .baseAddr = 0,
+ .icssInstId = 0,
+ .pruInstId = PRUICSS_PRU1,
+ .numTxI2s = 0,
+ .numRxI2s = 0,
+ .sampFreq = 0,
+ .bitsPerSlot = 0,
+ .i2sTxHostIntNum = 0,
+ .i2sRxHostIntNum = 0,
+ .i2sErrHostIntNum = 0,
+ .i2sTxIcssIntcSysEvt = 0,
+ .i2sRxIcssIntcSysEvt = 0,
+ .i2sErrIcssIntcSysEvt = 0,
+ .intcInitData = NULL,
+ },
+% }
+};
diff --git a/source/.meta/pru_i2s/pru_i2s_templates.c.xdt b/source/.meta/pru_i2s/pru_i2s_templates.c.xdt
new file mode 100644
index 000000000..88b49ba73
--- /dev/null
+++ b/source/.meta/pru_i2s/pru_i2s_templates.c.xdt
@@ -0,0 +1,178 @@
+%%{
+/*
+ * Copyright (C) 2024-2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * distribution and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Auto generated file - DO NOT MODIFY
+ * Generated by SysConfig from .syscfg file
+ */
+
+ let common = system.getScript("/common");
+ let module = system.modules["/pru_i2s/pru_i2s"];
+ let soc = system.getScript(`/drivers/soc/drivers_${common.getSocName()}`);
+ let device = common.getDeviceName();
+ let is_am263x_soc = (device === "am263x-cc") ? true : false;
+ let is_am261x_soc = (device === "am261x-lp") ? true : false;
+
+ /* Helper function to get ICSS instance number */
+ function getIcssInstanceNum(instanceName) {
+ if (instanceName === "ICSSG0" || instanceName === "ICSSM" || instanceName === "ICSSM0") {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ /* Helper function to get PRU slice number */
+ function getPruSliceNum(sliceName) {
+ if (sliceName === "PRU0") {
+ return 0; /* PRUICSS_PRU0 */
+ } else {
+ return 1; /* PRUICSS_PRU1 */
+ }
+ }
+
+ /* Helper function to get mode value */
+ function getModeValue(modeName) {
+ if (modeName === "I2S") {
+ return 0;
+ } else {
+ return 1; /* TDM */
+ }
+ }
+
+ /* Helper function to get INTC init data variable name */
+ function getIntcInitDataName(instance) {
+ let icss_num = getIcssInstanceNum(instance.instance);
+ if (is_am263x_soc) {
+ return "&icss_intc_initdata";
+ } else if (is_am261x_soc) {
+ if (icss_num === 0) {
+ return "&icss0_intc_initdata";
+ } else {
+ return "&icss1_intc_initdata";
+ }
+ } else {
+ if (icss_num === 0) {
+ return "&icssg0_intc_initdata";
+ } else {
+ return "&icssg1_intc_initdata";
+ }
+ }
+ }
+%%}
+% if (module && module.$instances.length > 0) {
+
+/* ========================================================================== */
+/* Include Files */
+/* ========================================================================== */
+
+#include
+#include
+#include
+
+/* ========================================================================== */
+/* PRU I2S Attrs Array */
+/* ========================================================================== */
+
+/*
+ * PRU I2S Attributes - Generated from SysConfig
+ *
+ * This structure contains all configuration parameters for each PRU I2S instance.
+ * All values are derived from the .syscfg file and are compile-time constants.
+ *
+ * Key characteristics:
+ * - Const structure (read-only, placed in flash/ROM)
+ * - All configuration from SysConfig (no runtime detection)
+ * - No base addresses stored (derived on-demand in driver)
+ * - INTC events from SysConfig
+ * - Clock frequencies explicit
+ */
+const PRUI2S_Attrs gPruI2sAttrs[CONFIG_PRU_I2S_NUM_INSTANCES] =
+{
+% for (let i = 0; i < module.$instances.length; i++) {
+% let instance = module.$instances[i];
+% let config = module.getInstanceConfig(instance);
+% let icss_num = getIcssInstanceNum(instance.instance);
+% let pru_slice = getPruSliceNum(instance.PRU_Slice);
+% let mode_val = getModeValue(instance.Mode);
+% let intc_data_name = getIntcInitDataName(instance);
+ /* Configuration `i` - `instance.$name` */
+ {
+ .instance = `i`,
+ .pruicss_instance = `icss_num`, /* `instance.instance` */
+ .pruicss_slice = `pru_slice`, /* `instance.PRU_Slice` */
+ .num_tx_channels = `instance.Num_Tx_Channels`,
+ .num_rx_channels = `instance.Num_Rx_Channels`,
+ .sampling_freq_khz = `instance.Sampling_Freq`,
+ .bits_per_slot = `instance.Bits_Per_Slot`,
+ .mode = `mode_val`, /* `instance.Mode` */
+ .tx_intc_event = `instance.Tx_INTC_Event`,
+ .rx_intc_event = `instance.Rx_INTC_Event`,
+ .err_intc_event = `instance.Err_INTC_Event`,
+ .core_clk_freq = `instance.Core_Clk_Freq`,
+ .intcInitData = `intc_data_name`,
+ },
+% }
+};
+
+/* Number of PRU I2S instances configured in SysConfig */
+const uint32_t CONFIG_PRU_I2S_NUM_INSTANCES = `module.$instances.length`;
+
+% } else {
+/* No PRU I2S instances configured in SysConfig */
+
+#include
+#include
+#include
+
+/* Empty attrs array - no instances configured */
+const PRUI2S_Attrs gPruI2sAttrs[1] = {
+ {
+ .instance = 0,
+ .pruicss_instance = 0,
+ .pruicss_slice = 0,
+ .num_tx_channels = 0,
+ .num_rx_channels = 0,
+ .sampling_freq_khz = 48,
+ .bits_per_slot = 32,
+ .mode = 0,
+ .tx_intc_event = 18,
+ .rx_intc_event = 19,
+ .err_intc_event = 20,
+ .core_clk_freq = 200000000,
+ .intcInitData = NULL,
+ }
+};
+
+const uint32_t CONFIG_PRU_I2S_NUM_INSTANCES = 0;
+% }
diff --git a/source/.meta/pru_i2s/pru_i2s_templates.h.xdt b/source/.meta/pru_i2s/pru_i2s_templates.h.xdt
new file mode 100644
index 000000000..6aa441022
--- /dev/null
+++ b/source/.meta/pru_i2s/pru_i2s_templates.h.xdt
@@ -0,0 +1,140 @@
+%%{
+/*
+ * Copyright (C) 2024-2025 Texas Instruments Incorporated
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * distribution and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Auto generated file - DO NOT MODIFY
+ * Generated by SysConfig from .syscfg file
+ */
+
+ let common = system.getScript("/common");
+ let module = system.modules["/pru_i2s/pru_i2s"];
+
+ /* Helper function to get PRU ID string for firmware selection */
+ function getPruIdString(sliceName) {
+ if (sliceName === "PRU0") {
+ return "0";
+ } else {
+ return "1";
+ }
+ }
+%%}
+% if (module && module.$instances.length > 0) {
+
+/* ========================================================================== */
+/* PRU I2S Configuration */
+/* ========================================================================== */
+
+/*
+ * PRU I2S SysConfig-generated configuration
+ *
+ * This header provides:
+ * - Instance index defines for each configured PRU I2S instance
+ * - Extern declaration for attrs array
+ * - Firmware selection helpers
+ */
+
+#ifndef PRU_I2S_CONFIG_H_
+#define PRU_I2S_CONFIG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ========================================================================== */
+/* Include Files */
+/* ========================================================================== */
+
+#include
+
+/* ========================================================================== */
+/* Instance Defines */
+/* ========================================================================== */
+
+/*
+ * SysConfig-generated instance indices
+ * Use these defines in application code to reference PRU I2S instances
+ */
+% for (let i = 0; i < module.$instances.length; i++) {
+% let instance = module.$instances[i];
+#define `instance.$name` (`i`U)
+% let pru_id = getPruIdString(instance.PRU_Slice);
+#define `instance.$name`_PRUICSS_PRU_ID (`pru_id`)
+% }
+
+/* Number of configured PRU I2S instances */
+#define CONFIG_PRU_I2S_NUM_INSTANCES (`module.$instances.length`U)
+
+/* ========================================================================== */
+/* Global Variables */
+/* ========================================================================== */
+
+/*
+ * PRU I2S Attrs Array
+ * Extern declaration for the attrs array generated in ti_drivers_config.c
+ * Applications can access attrs directly: gPruI2sAttrs[CONFIG_PRU_I2S0]
+ */
+extern const PRUI2S_Attrs gPruI2sAttrs[CONFIG_PRU_I2S_NUM_INSTANCES];
+
+/* Number of instances */
+extern const uint32_t CONFIG_PRU_I2S_NUM_INSTANCES;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PRU_I2S_CONFIG_H_ */
+
+% } else {
+/* No PRU I2S instances configured in SysConfig */
+
+#ifndef PRU_I2S_CONFIG_H_
+#define PRU_I2S_CONFIG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+/* No instances configured */
+#define CONFIG_PRU_I2S_NUM_INSTANCES (0U)
+
+extern const PRUI2S_Attrs gPruI2sAttrs[1];
+extern const uint32_t CONFIG_PRU_I2S_NUM_INSTANCES;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PRU_I2S_CONFIG_H_ */
+% }