This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How to run NDK Ethernet on C66x DSP of AM572x EVM

Other Parts Discussed in Thread: SYSBIOS, AM5728

I didn't receive much help on the forum for resolving this under other threads so I am sharing a solution that works for me.  The NDK can run on the C66x core but the current transport driver does not support the interrupt mapping required by the C66x, EventCombiner.  Thus you have to add it to the ethernet driver and then rebuild the PDK.  Presently I am using pdk_am57xx_101 and processor_sdk_rtos_am57xx_2_00_01_07.  The driver is located in C:\ti\pdk_am57xx_1_0_1\packages\ti\transport\ndk\nimu\src\v4.  Edit cpsw_ethdriver.c, removing the existing Interrupt_init() routing and replacing it with the code below.  You can then rebuild the PDK using the directions from the wiki:

http://processors.wiki.ti.com/index.php/Rebuilding_The_PDK

The interrupts in the NIMU test project should be mapped something like:

#define GMAC_SW_IRQ_RX_PULSE_INT_NUM (4) // Low level DSP Interrupt desired, 4 to 15 valid
#define GMAC_SW_IRQ_TX_PULSE_INT_NUM (5) // Low level DSP Interrupt desired, 4 to 15 valid
#define GMAC_SW_IRQ_RX_THRESH_PULSE_INT_NUM (CSL_XBAR_INST_DSP1_IRQ_76) // used to map DSP Event
#define GMAC_SW_IRQ_MISC_PULSE_INT_NUM (CSL_XBAR_INST_DSP1_IRQ_77) // used to map DSP Event

Since NIMU_Config structure does not contain enough entries to handle the multiple layers of mapping needed for the interrupts the rxThreshIntrNum and miscIntrNum interrupt entries are used to pass the DSP Event being used that is mapped via the crossbar.  They don't seem to be used by the PDK.

NIMU_Config NIMU_config =
{
CSL_DSP_ISS_REGS,
CSL_DSP_IMDIO_REGS,
CSL_DSP_IWR_REGS,
CSL_DSP_IALE_REGS,
CSL_DSP_ICPDMA_REGS,
(CSL_DSP_ISS_REGS + 0x2000U),
CSL_DSP_IPORT_REGS,
(CSL_DSP_ISS_REGS + 0x900U),
GMAC_SW_IRQ_RX_PULSE_INT_NUM,
GMAC_SW_IRQ_RX_THRESH_PULSE_INT_NUM,
GMAC_SW_IRQ_TX_PULSE_INT_NUM,
GMAC_SW_IRQ_MISC_PULSE_INT_NUM,
{
{
CSL_DSP_IPORT_REGS,
CSL_DSP_ISL1_REGS,
0U,

},
{
CSL_DSP_IPORT_REGS,
CSL_DSP_ISL2_REGS,
1U,

}
}
};

Create yourself a Sysbios project using the attached cfg and main.c files (will attempt to put in following post)  which originated from the NIMU_BasicExample_evmAM572x_armExampleproject.  To debug you must run the boardinit() code from the arm project on the A15, then load your program into the DSP1 core and execute it.  You should be able to ping 192.168.1.4, change the IP address in the cfg file if needed.

Edit C:\ti\pdk_am57xx_1_0_1\packages\ti\transport\ndk\nimu\src\v4\cpsw_ethdriver.c and replace Interrupt_init() with the below code, then rebuild PDK, ignore XDC warnings with regards to typedef name already declared:

#if defined(ti_targets_elf_C66) && (defined(SOC_AM571x) || defined(SOC_AM572x))
#include <ti/sysbios/family/c64p/EventCombiner.h>
#include <ti/sysbios/family/shared/vayu/IntXbar.h>
#include <ti/csl/cslr_device.h>
#include <ti/csl/soc/am572x/src/cslr_soc.h>

#endif

void Interrupt_init(void)
{
HwiP_Handle rxHwiHandle;
HwiP_Handle txHwiHandle;
static Uint32 cookie = 0;

cookie = NIMU_osalHardwareIntDisable();

HwiP_Params hwiParams;

NIMU_osalHwiParamsInit(&hwiParams);

#if defined(ti_targets_elf_C66) && (defined(SOC_AM571x) || defined(SOC_AM572x))

NIMU_drv_log("RX Interrupt being setup using EventCombiner.\n");

// Maps crossbar input to DSP event. Use NIMU_config.rxThreshIntrNum as place holder since existing
// structure does not allow for it and it does not seem to be used elsewhere. The Crossbar input
// is hard coded since it does not change on the AM5728.
IntXbar_connectIRQ(NIMU_config.rxThreshIntrNum, CSL_XBAR_GMAC_SW_IRQ_RX_PULSE); // Maps crossbar input to DSP event

/* Plug an ISR for DSP event from NIMU_config table */
EventCombiner_dispatchPlug(NIMU_config.rxThreshIntrNum, &Cpsw_HwIntRx, NIMU_config.rxThreshIntrNum, TRUE);
hwiParams.arg = NIMU_config.rxThreshIntrNum / 32; // There are up to 128 events in array of ints
hwiParams.evtId = hwiParams.arg;
hwiParams.priority = 0x20; //TODO Rename
rxHwiHandle = NIMU_osalRegisterInterrupt(NIMU_config.rxIntrNum, &EventCombiner_dispatch, &hwiParams);
#else
hwiParams.arg = (uintptr_t)NULL;
hwiParams.evtId = NIMU_config.rxIntrNum;
hwiParams.priority = 0x20; //TODO Rename
// Set interrupt handler to be EventCombiner_dispatch, it will jump to Cpsw_HwIntTx after analyzing interrupt
rxHwiHandle = NIMU_osalRegisterInterrupt(NIMU_config.rxIntrNum, &Cpsw_HwIntRx, &hwiParams);
#endif

if(rxHwiHandle == NULL)
NIMU_drv_log("Error setting up Rx Interrupts \n");

#if defined(ti_targets_elf_C66) && (defined(SOC_AM571x) || defined(SOC_AM572x))

NIMU_drv_log("TX Interrupt being setup using EventCombiner.\n");

// Maps crossbar input to DSP event. Use NIMU_config.rxThreshIntrNum as place holder since existing
// structure does not allow for it and it does not seem to be used elsewhere. The Crossbar input
// is hard coded since it does not change on the AM5728.
IntXbar_connectIRQ(NIMU_config.miscIntrNum, CSL_XBAR_GMAC_SW_IRQ_TX_PULSE); // Maps crossbar input to DSP event

/* Plug an ISR for DSP event from NIMU_config table */
EventCombiner_dispatchPlug(NIMU_config.miscIntrNum, &Cpsw_HwIntTx, NIMU_config.miscIntrNum, TRUE);
hwiParams.arg = NIMU_config.miscIntrNum / 32; // There are up to 128 events in array of ints
hwiParams.evtId = hwiParams.arg;
hwiParams.priority = 0x20; //TODO Rename
// Set interrupt handler to be EventCombiner_dispatch, it will jump to Cpsw_HwIntTx after analyzing interrupt
txHwiHandle = NIMU_osalRegisterInterrupt(NIMU_config.txIntrNum, &EventCombiner_dispatch, &hwiParams);
#else
hwiParams.arg = (uintptr_t)NULL;
hwiParams.evtId = NIMU_config.txIntrNum;
hwiParams.priority = 0x20; //TODO Rename
txHwiHandle = NIMU_osalRegisterInterrupt(NIMU_config.txIntrNum, &Cpsw_HwIntTx, &hwiParams);
#endif

if(txHwiHandle == NULL)
NIMU_drv_log("Error setting up Rx Interrupts \n");

/* Restore global interrupts */
NIMU_osalHardwareIntRestore(cookie);
}

  • main.c code:

    /*
    * ======== main.c ========
    */

    #include <xdc/std.h>

    #include <xdc/runtime/Error.h>
    #include <xdc/runtime/System.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/transport/ndk/nimu/src/v4/cpsw_ethdriver.h>
    #include <ti/transport/ndk/nimu/src/v4/cpsw_impl.h>
    #include <ti/csl/soc.h>
    #include <ti/csl/cslr_device.h>
    #include <ti/board/board.h>

    #include <ti/drv/uart/UART.h>
    #include <ti/drv/uart/UART_osal.h>
    #include <ti/drv/uart/UART_stdio.h>

    #define IO_CONSOLE
    #ifndef IO_CONSOLE
    #define NIMU_log UART_printf
    #else
    #define NIMU_log printf
    #endif

    /**Phy address of the CPSW port 1*/
    #define CPSW_PORT0_PHY_ADDR_EVM 1
    /**Phy address of the CPSW port 1*/
    #define CPSW_PORT1_PHY_ADDR_EVM 2

    #define GMAC_SW_IRQ_RX_PULSE_INT_NUM (4) // Low level DSP Interrupt desired, 4 to 15 valid
    #define GMAC_SW_IRQ_TX_PULSE_INT_NUM (5) // Low level DSP Interrupt desired, 4 to 15 valid
    #define GMAC_SW_IRQ_RX_THRESH_PULSE_INT_NUM (CSL_XBAR_INST_DSP1_IRQ_76) // used to map DSP Event
    #define GMAC_SW_IRQ_MISC_PULSE_INT_NUM (CSL_XBAR_INST_DSP1_IRQ_77) // used to map DSP Event

    #define MAX_TABLE_ENTRIES 3

    /* ========================================================================== */
    /* Global Variables */
    /* ========================================================================== */

    NIMU_Config NIMU_config =
    {
    CSL_DSP_ISS_REGS,
    CSL_DSP_IMDIO_REGS,
    CSL_DSP_IWR_REGS,
    CSL_DSP_IALE_REGS,
    CSL_DSP_ICPDMA_REGS,
    (CSL_DSP_ISS_REGS + 0x2000U),
    CSL_DSP_IPORT_REGS,
    (CSL_DSP_ISS_REGS + 0x900U),
    GMAC_SW_IRQ_RX_PULSE_INT_NUM,
    GMAC_SW_IRQ_RX_THRESH_PULSE_INT_NUM,
    GMAC_SW_IRQ_TX_PULSE_INT_NUM,
    GMAC_SW_IRQ_MISC_PULSE_INT_NUM,
    {
    {
    CSL_DSP_IPORT_REGS,
    CSL_DSP_ISL1_REGS,
    0U,

    },
    {
    CSL_DSP_IPORT_REGS,
    CSL_DSP_ISL2_REGS,
    1U,

    }
    }
    };

    /**Task handle for EIP*/
    Task_Handle main_task;

    static int nimu_device_index = 0U;

    MAC_CONFIG mac_configuration;

    NIMU_DEVICE_TABLE_ENTRY NIMUDeviceTable[MAX_TABLE_ENTRIES];

    /*
    * ======== taskFxn ========
    */
    Void TaskFxn(UArg a0, UArg a1)
    {
    NIMU_log("\n\rSYS/BIOS Ethernet/IP (CPSW) Sample application\n\r");

    Task_sleep(10);

    NIMU_log("exit taskFxn()\n");

    System_flush(); /* force SysMin output to console */
    }


    extern int CpswEmacInit (STKEVENT_Handle hEvent);

    /* ========================================================================== */
    /* Function Definitions */
    /* ========================================================================== */

    /**
    * \brief This function returns the MAC address for the EVM
    *
    * \param addrIdx the MAC address index.
    * \param macAddr the Pointer where the MAC address shall be stored
    * 'addrIdx' can be either 0 or 1
    *
    * \return None.
    */
    void EVMMACAddrGet(uint32_t addrIdx, uint8_t *macAddr)
    {
    macAddr[0U] = (((CSL_control_coreRegs *) CSL_DSP_CTRL_MODULE_CORE_CORE_REGISTERS_REGS)->MAC_ID_SW_0
    >> 16U) & 0xFFU;
    macAddr[1U] = (((CSL_control_coreRegs *) CSL_DSP_CTRL_MODULE_CORE_CORE_REGISTERS_REGS)->MAC_ID_SW_0
    >> 8U) & 0xFFU;
    macAddr[2U] = (((CSL_control_coreRegs *) CSL_DSP_CTRL_MODULE_CORE_CORE_REGISTERS_REGS)->MAC_ID_SW_0)
    & 0xFF;
    macAddr[3U] = (((CSL_control_coreRegs *) CSL_DSP_CTRL_MODULE_CORE_CORE_REGISTERS_REGS)->MAC_ID_SW_1
    >> 16U) & 0xFFU;
    macAddr[4U] = (((CSL_control_coreRegs *) CSL_DSP_CTRL_MODULE_CORE_CORE_REGISTERS_REGS)->MAC_ID_SW_1
    >> 8U) & 0xFFU;
    macAddr[5U] = (((CSL_control_coreRegs *) CSL_DSP_CTRL_MODULE_CORE_CORE_REGISTERS_REGS)->MAC_ID_SW_1)
    & 0xFFU;
    }

    void CSL_xbarDspIrqConfigure(Uint32 dspInst, Uint32 irqNumIdx, CSL_XbarIrq xbarIrq)
    {
    CSL_control_intr_dmaRegs *ctrlCoreIntrDmaReg =
    (CSL_control_intr_dmaRegs *) CSL_DSP_IRQ_DMARQ_CROSSBAR_REGISTERS_REGS;
    CSL_control_coreRegs *ctrlCoreReg =
    (CSL_control_coreRegs *) CSL_DSP_CTRL_MODULE_CORE_CORE_REGISTERS_REGS;
    Uint32 regIdx = (irqNumIdx - 1U) / 2U;
    Uint32 regLsb = (((irqNumIdx - 1U) % 2U) * 16U);
    Uint32 regMsb = regLsb + 16U;

    if((CSL_XBAR_IRQ_MIN < xbarIrq) && (CSL_XBAR_IRQ_MAX > xbarIrq))
    {
    if ((0U < irqNumIdx) && (CSL_DSP_IRQ_XBAR_COUNT >= irqNumIdx))
    {
    if(1U == dspInst)
    {
    ctrlCoreReg->MMR_LOCK_2 = 0xF757FDC0U;
    CSL_FINSR(ctrlCoreIntrDmaReg->DSP1_IRQ[regIdx],
    regMsb, regLsb, xbarIrq);
    ctrlCoreReg->MMR_LOCK_2 = 0xFDF45530U;
    }
    else if(2U == dspInst)
    {
    ctrlCoreReg->MMR_LOCK_2 = 0xF757FDC0U;
    CSL_FINSR(ctrlCoreIntrDmaReg->DSP2_IRQ[regIdx],
    regMsb, regLsb, xbarIrq);
    ctrlCoreReg->MMR_LOCK_2 = 0xFDF45530U;
    }
    }
    }
    }

    /*
    * ======== main ========
    */
    Int main()
    {
    // Board_initCfg boardCfg;
    Task_Params taskParams;

    NIMU_log("enter main()\n");
    // boardCfg = BOARD_INIT_UNLOCK_MMR | BOARD_INIT_PINMUX_CONFIG | // Run this from dummy A15 program first
    // BOARD_INIT_MODULE_CLOCK | BOARD_INIT_UART_STDIO;
    // Board_init(boardCfg);


    CSL_xbarDspIrqConfigure(1,CSL_XBAR_INST_DSP1_IRQ_76, CSL_XBAR_GMAC_SW_IRQ_RX_PULSE);
    CSL_xbarDspIrqConfigure(1,CSL_XBAR_INST_DSP1_IRQ_77, CSL_XBAR_GMAC_SW_IRQ_TX_PULSE);
    /* Select RGMII 2 ports GMIIx_SEL = 2 for RGMII*/
    CSL_FINS (((CSL_control_coreRegs *) CSL_DSP_CTRL_MODULE_CORE_CORE_REGISTERS_REGS)->CONTROL_IO_1,
    CONTROL_CORE_CONTROL_IO_1_GMII1_SEL, 2U);
    CSL_FINS (((CSL_control_coreRegs *) CSL_DSP_CTRL_MODULE_CORE_CORE_REGISTERS_REGS)->CONTROL_IO_1,
    CONTROL_CORE_CONTROL_IO_1_GMII2_SEL, 2U);

    /*GMAC RESET ISOLATION Enable*/
    CSL_FINS (((CSL_control_coreRegs *) CSL_DSP_CTRL_MODULE_CORE_CORE_REGISTERS_REGS)->CONTROL_IO_2,
    CONTROL_CORE_CONTROL_IO_2_GMAC_RESET_ISOLATION_ENABLE, 0U);
    CSL_FINS (((CSL_control_coreRegs *) CSL_DSP_CTRL_MODULE_CORE_CORE_REGISTERS_REGS)->CONTROL_IO_2,
    CONTROL_CORE_CONTROL_IO_2_GMAC_RESET_ISOLATION_ENABLE, 1U);

    mac_configuration.phyAddr[0] = CPSW_PORT0_PHY_ADDR_EVM;
    mac_configuration.phyAddr[1] = CPSW_PORT1_PHY_ADDR_EVM;
    mac_configuration.numberPorts = 2;
    mac_configuration.resvd = 1;
    mac_configuration.tlk110Flag =1;
    mac_configuration.macModeFlags = CPSW_CONFIG_MODEFLG_GIGABIT| CPSW_CONFIG_MODEFLG_FULLDUPLEX;

    Task_Params_init(&taskParams);
    taskParams.priority = 12;
    taskParams.stackSize = 0x1400;
    System_printf("Invoke Task_create().\n");
    NIMU_log("Task_create().\n");
    main_task = Task_create (TaskFxn, &taskParams, NULL);
    NIMU_log("Main task created.\n");

    NIMUDeviceTable[nimu_device_index++].init = &CpswEmacInit ;
    NIMUDeviceTable[nimu_device_index].init = NULL ;

    NIMU_log("start bios...\n");
    BIOS_start(); /* does not return */
    return(0);
    }
  • app.cfg code:

    var Defaults = xdc.useModule('xdc.runtime.Defaults');
    var Diags = xdc.useModule('xdc.runtime.Diags');
    var Error = xdc.useModule('xdc.runtime.Error');
    var Log = xdc.useModule('xdc.runtime.Log');
    var LoggerBuf = xdc.useModule('xdc.runtime.LoggerBuf');
    var Main = xdc.useModule('xdc.runtime.Main');

    /* create a default heap */
    var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
    //var ti_sysbios_family_c64p_Hwi = xdc.useModule('ti.sysbios.family.c64p.Hwi');
    //var EventCombiner = xdc.useModule('ti.sysbios.family.c64p.EventCombiner');
    var heapMemParams = new HeapMem.Params();
    heapMemParams.size = 0x100000;

    var Memory = xdc.useModule('xdc.runtime.Memory');
    Memory.defaultHeapInstance = HeapMem.create(heapMemParams);

    var SysStd = xdc.useModule('xdc.runtime.SysStd');
    //var SysMin = xdc.useModule('xdc.runtime.SysMin');
    //SysMin.bufSize = 0x1000;
    //SysMin.flushAtExit = true;

    var System = xdc.useModule('xdc.runtime.System');
    //System.SupportProxy = SysMin;
    System.SupportProxy = SysStd;

    var Text = xdc.useModule('xdc.runtime.Text');

    var BIOS = xdc.useModule('ti.sysbios.BIOS');
    var Clock = xdc.useModule('ti.sysbios.knl.Clock');
    var Timer = xdc.useModule('ti.sysbios.timers.dmtimer.Timer');
    var Swi = xdc.useModule('ti.sysbios.knl.Swi');
    var Task = xdc.useModule('ti.sysbios.knl.Task');
    var Semaphore = xdc.useModule('ti.sysbios.knl.Semaphore');
    //var Hwi = xdc.useModule('ti.sysbios.hal.Hwi');
    var ti_sysbios_hal_Hwi = xdc.useModule('ti.sysbios.hal.Hwi');
    //var Hwi = xdc.useModule('ti.sysbios.hal.Hwi');
    //var Hwi = xdc.useModule('ti.sysbios.family.c64p.Hwi');
    //var ECM = xdc.useModule('ti.sysbios.family.c64p.EventCombiner');
    var IntXbar = xdc.useModule('ti.sysbios.family.shared.vayu.IntXbar');

    /* Load the OSAL package */
    var osType = "tirtos"
    var Osal = xdc.useModule('ti.osal.Settings');
    Osal.osType = osType;

    /* Load the UART package */
    var UART = xdc.loadPackage('ti.drv.uart');

    /* Load the I2C package */
    var I2C = xdc.loadPackage('ti.drv.i2c');

    /* Load the Board package and set the board name */
    var Board = xdc.loadPackage('ti.board');
    Board.Settings.boardName = "evmAM572x";


    var Global = xdc.useModule('ti.ndk.config.Global');
    var Tcp = xdc.useModule('ti.ndk.config.Tcp');
    var Udp = xdc.useModule('ti.ndk.config.Udp');
    var Telnet = xdc.useModule('ti.ndk.config.Telnet');
    //var DhcpClient = xdc.useModule('ti.ndk.config.DhcpClient');
    var Icmp = xdc.useModule('ti.ndk.config.Icmp');
    var Ip = xdc.useModule('ti.ndk.config.Ip');

    var socType = "am572x";
    var Nimu = xdc.loadPackage('ti.transport.ndk.nimu');
    Nimu.Settings.socType = socType;

    /* Settings for static IP configuration */
    Ip.ResolveIP = false;
    Ip.CallByIP = false;
    Ip.autoIp = false;
    Ip.address = "192.168.1.4";
    Ip.mask = "255.255.255.0";
    Ip.gatewayIpAddr = "192.168.1.1";

    /*
    * Uncomment this line to globally disable Asserts.
    * All modules inherit the default from the 'Defaults' module. You
    * can override these defaults on a per-module basis using Module.common$.
    * Disabling Asserts will save code space and improve runtime performance.
    Defaults.common$.diags_ASSERT = Diags.ALWAYS_OFF;
    */

    /*
    * Uncomment this line to keep module names from being loaded on the target.
    * The module name strings are placed in the .const section. Setting this
    * parameter to false will save space in the .const section. Error and
    * Assert messages will contain an "unknown module" prefix instead
    * of the actual module name.
    Defaults.common$.namedModule = false;
    */

    /*
    * Minimize exit handler array in System. The System module includes
    * an array of functions that are registered with System_atexit() to be
    * called by System_exit().
    */
    System.maxAtexitHandlers = 4;

    /*
    * Uncomment this line to disable the Error print function.
    * We lose error information when this is disabled since the errors are
    * not printed. Disabling the raiseHook will save some code space if
    * your app is not using System_printf() since the Error_print() function
    * calls System_printf().
    Error.raiseHook = null;
    */

    /*
    * Uncomment this line to keep Error, Assert, and Log strings from being
    * loaded on the target. These strings are placed in the .const section.
    * Setting this parameter to false will save space in the .const section.
    * Error, Assert and Log message will print raw ids and args instead of
    * a formatted message.
    Text.isLoaded = false;
    */

    /*
    * Uncomment this line to disable the output of characters by SysMin
    * when the program exits. SysMin writes characters to a circular buffer.
    * This buffer can be viewed using the SysMin Output view in ROV.
    SysMin.flushAtExit = false;
    */

    /*
    * The BIOS module will create the default heap for the system.
    * Specify the size of this default heap.
    */
    //BIOS.heapSize = 0x1000;

    /*
    * Build a custom SYS/BIOS library from sources.
    */
    BIOS.libType = BIOS.LibType_Custom;

    /* System stack size (used by ISRs and Swis) */
    Program.stack = 0x2000;

    /* Circular buffer size for System_printf() */
    //SysMin.bufSize = 0x200;

    /*
    * Create and install logger for the whole system
    */
    var loggerBufParams = new LoggerBuf.Params();
    loggerBufParams.numEntries = 16;
    var logger0 = LoggerBuf.create(loggerBufParams);
    Defaults.common$.logger = logger0;
    Main.common$.diags_INFO = Diags.ALWAYS_ON;

    //System.SupportProxy = SysMin;

    Global.ndkTickPeriod = 100;
    Global.kernTaskPriLevel = 11;
    Global.serviceReportHook = null;
    Global.IPv6 = false;
    Global.ndkThreadStackSize = 8192;
    Global.lowTaskStackSize = 3072;
    Global.normTaskStackSize = 4096;
    Global.highTaskStackSize = 5120;
    Global.pktNumFrameBufs = 192;
    Global.pbmDataSection = ".far:NDK_PACKETMEM";
    Global.memDataSection = ".far:NDK_MMBUFFER";
  • Thanks for sharing this on the forum!
  • Nice job and thanks for posting the solution!