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 + +![Test Setup AM263x](images/setup_am263x.png) + +**Block Diagram:** +![Block Diagram AM263x](images/block_diagram_am263x.png) + +**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 + +![Test Setup AM261x](images/setup_am261x.png) + +**Block Diagram:** +![Block Diagram AM261x](images/block_diagram_am261x.jpg) + +**Connection Steps:** +1. **Configure PCM6260-Q1 EVM:** + - Connect PC via USB cable + - Set SW2 for External ASI mode: + ![PCM ASI Setting](images/pcm1.png) + +2. **Audio Clock Connections:** + ![PCM Jumper Headers](images/pcm2.png) + - 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) +![PRU I2S TX Architecture](images/pru_i2s_tx_arch.png) +![TX Firmware Flow](images/firmware_flow_tx.jpg) + +**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) +![PRU I2S RX Architecture](images/pru_i2s_rx_arch.png) +![RX Firmware Flow](images/firmware_flow_rx.jpg) + +**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 + ![PCM Channel Config](images/pcm_channel_config.png) + ![PCM Clock Signals](images/pcm_clock_signals.png) + +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 + ![RX Buffer Capture](images/rx_buffer_capture.png) + +**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_ */ +% }