AM64x MCU+ SDK  10.01.00
PRUICSS

Programmable Real-Time Unit and Industrial Communication Subsystem(PRU-ICSS) driver provides a well-defined API layer which allows applications to use the PRU-ICSS. PRU-ICSS is firmware programmable and can take on various personalities like Industrial Communication Protocol Switch (for protocols like EtherCAT, Profinet, EtherNet/IP), Ethernet Switch, Ethernet MAC, Industrial Drives, etc.

Features Supported

  • PRU control features like enabling/disabling/resetting a Programmable Real-Time Units (PRU0 and PRU1), Auxiliary Programmable Real-Time Units (RTU_PRU0 and RTU_PRU1) or Transmit Programmable Real-Time Units (TX_PRU0 and TX_PRU1) core
  • Loading the firmware in PRU cores
  • Read/Write/Reset different memories inside PRU-ICSS
  • PRU and Host Event management. It does mapping of sys_evt/channel/hosts in the INTC module. APIs to register interrupt handler for events, generate an event, wait for occurrence of an event, and clear an event.
  • Basic configurations in registers like GPCFG, MII_RT_G_CFG, ICSSG_SA_MX
  • IEP clock selection, IEP counter enable/disable, IEP counter increment configuration
  • PRU Constant Table Configuration

SysConfig Features

Note
It is strongly recommend to use SysConfig where it is available instead of using direct SW API calls. This will help simplify the SW application and also catch common mistakes early in the development cycle.
  • Option to select the PRU-ICSS instance
  • Option to select the Core Clock Frequency
  • Option to enable the IEP Sync Mode
  • Option to select the IEP Clock Frequency if IEP Sync Mode is disabled
  • Optional sub-module to select pin configurations
  • Optional sub-module to select ICSS interrupt controller signals mapping
  • Based on above parameters, the SysConfig generated code does following:
    • Call PRUICSS_init in System_init, and PRUICSS_deinit in System_deinit
    • Enable the Core Clock and set the selected frequency
    • Create macros like CONFIG_PRU_ICSS1 using the name passed in SysConfig. This is used as an input to PRUICSS_open API.
    • Set hardware register for enabling IEP Sync mode in System_init

PRUICSS Interrupt Controller

The interrupt controller (INTC) module maps interrupts coming from different parts of the device (mapped to PRU-ICSS instance) to a reduced set of interrupt channels.

The interrupt controller has the following features:

  • Capturing up to 160 Events (inputs)
    • Upper 96 are external events
    • Lower 64 are internal events
  • Supports up to 20 output interrupt channels
  • Generation of 20 Host Interrupts
    • 2 Host Interrupts shared between the PRUs (PRU0 and PRU1) and TX_PRUs (TX_PRU0 and TX_PRU1).
    • 2 Host Interrupts for the RTU PRUs (RTU_PRU0 and RTU_PRU1).
    • 8 Host Interrupts exported from the PRU_ICSSG internal INTC for signaling the device level interrupt controllers (pulse and level provided).
    • 8 Host Interrupts (event 12 through 19) for the Task Managers.
  • Each event can be enabled and disabled.
  • Each host event can be enabled and disabled.
  • Hardware prioritization of events.

Following are some important points related to INTC configuration:

  • Any of the 160 internal interrupts can be mapped to any of the 20 channels.
  • Multiple interrupts can be mapped to a single channel.
  • An interrupt should not be mapped to more than one channel.
  • Any of the 20 channels can be mapped to any of the 20 host interrupts. It is recommended to map channel "x" to host interrupt "x", where x is from 0 to 19.
  • A channel should not be mapped to more than one host interrupt
  • For channels mapping to the same host interrupt, lower number channels have higher priority.
  • For interrupts on same channel, priority is determined by the hardware interrupt number. The lower the interrupt number, the higher the priority.
  • Host Interrupt 0 is connected to bit 30 in register 31 (R31) of PRU0 and PRU1 in parallel.
  • Host Interrupt 1 is connected to bit 31 in register 31 (R31) for PRU0 and PRU1 in parallel.
  • Host Interrupts 2 through 9 exported from PRU-ICSS and mapped to device level interrupt controllers.
  • Host Interrupt 10 is connected to bit 30 in register 31 (R31) to both RTU_PRU0 and RTU_PRU1 in parallel.
  • Host Interrupt 11 is connected to bit 31 in register 31 (R31) to both RTU_PRU0 and RTU_PRU1 in parallel.
  • Host Interrupts 12 through 19 are connected to each of the 4 Task Managers.

For industrial communication protocol examples running on R5F, Host Interrupts 2 through 9 exported from PRU-ICSS are used for signalling an interrupt to R5F. As this mapping is programmable and varies from example to example, we have a *_pruss_intc_mapping.h file for different protocol examples which is used for passing PRUICSS_IntcInitData structure while calling PRUICSS_intcInit API.

Sysconfig for INTC

You may use the sysconfig interface for PRU_ICSSG Local INTC mapping.

Sysconfig will create (see on right side generated code)

  • PRUICSS_IntcInitData structures for interrupt mapping named icss0_intc_initdata, icss1_intc_initdata for ICSS0, ICSS1 instances respectively in ti_drivers_config.c. This is for use in main app to initialize interrupt settings by passing these to PRUICSS_intcInit. The previous interrupt settings are overwritten by this so please use it only once to initialize the interrupts.

User Defined INTC Settings

Following is an example of one mapping from ${SDK_INSTALL_PATH}/source/industrial_comms/ethercat_slave/icss_fwhal/tiesc_pruss_intc_mapping.h used for EtherCAT SubDevice.

The following line maps PRU_ARM_EVENT2 to CHANNEL6.

{PRU_ARM_EVENT2, CHANNEL6, SYS_EVT_POLARITY_HIGH, SYS_EVT_TYPE_EDGE},\

CHANNEL6 is mapped to the fourth host interrupt mapped to device level interrupt controller(Host Interrupt 6 out of 20) through this line.

{CHANNEL6, PRU_EVTOUT4}

In AM64x, PRU_ICSSG0_PR1_HOST_INTR_PEND_0-PRU_ICSSG0_PR1_HOST_INTR_PEND_7 (8 host interrupts) are mapped to R5FSS0_CORE0_INTR_IN_120-R5FSS0_CORE0_INTR_IN_127. This values are for ICSSG0 events mapped to R5FSS0 CORE0. For details regarding interrupt numbers on other cores, please refer to "9.4 Interrupt Sources" section in Technical Reference Manual(TRM) of AM64x, or corresponding section in TRM of other SoCs. These interrupt numbers can change from SoC to SoC, so please consult TRM before making any modifications to the interrupt map.

For the example mentioned above, interrupt number 124 (R5FSS0_CORE0_INTR_IN_124) should be used for intrNum parameter for PRUICSS_registerIrqHandler. PRUICSS_registerIrqHandler creates Hwi instance using HwiP_construct API with the intrNum passed,

This mapping alone determines which interrupt number on R5F will be associated with a particular interrupt from PRUICSS. For example, in the code shown above, where `PRU_ARM_EVENT2 maps to CHANNEL6, and CHANNEL6 maps to PRU_EVTOUT4 can be modified to following, and the interrupt number on R5F would still remain the same.

{PRU_ARM_EVENT2, CHANNEL7, SYS_EVT_POLARITY_HIGH, SYS_EVT_TYPE_EDGE},\
{CHANNEL7, PRU_EVTOUT4}

But the usefulness of channels is that channels allow us to map multiple PRU events to a single channel and in turn to a single host interrupt. For example, take a look at the following mapping used for link interrupt.

{MII_LINK0_EVENT, CHANNEL1, SYS_EVT_POLARITY_HIGH, SYS_EVT_TYPE_PULSE},\
{MII_LINK1_EVENT, CHANNEL1, SYS_EVT_POLARITY_HIGH, SYS_EVT_TYPE_PULSE},\
{CHANNEL1, PRU1}

This configuration maps both Port 0 and Port 1 link interrupts to a single channel and in turn to a single host interrupt for PRU1 (Host Interrupt 1 out of 20).

Note
Please refer to section "6.4.7 PRU_ICSSG Local INTC" in Technical Reference Manual(TRM) of AM64x for more details on INTC module

Example Usage

Include the below file to access the APIs

Instance Open Example

/*Use CONFIG_PRU_ICSS1 macro as parameter to PRUICSS_open */
gPruicssHandle = PRUICSS_open(CONFIG_PRU_ICSS1);
DebugP_assert(gPruicssHandle != NULL);

Sequence for loading a firmware on PRU and running the PRU core

/* Reset and disable PRU core */
PRUICSS_resetCore(gPruicssHandle, PRUICSS_PRU0);
/* Register an Interrupt Handler for an event */
pruEvtoutNum,
intrNum,
eventNum,
waitEnable,
irqHandler);
/* API to do Interrupt-Channel-host mapping */
PRUICSS_intcInit(gPruicssHandle, &pruicssIntcInitData);
/* Load the IRAM in PRU */
PRUICSS_writeMemory(gPruicssHandle,
0,
(uint32_t *) pruFirmware,
pruFirmwareLength);
/* Enable PRU */
PRUICSS_enableCore(gPruicssHandle, PRUICSS_PRU0);

PRUICSS ENET Driver

The ICSSG can be used as a generic Layer 2 Ethernet Switch or Dual Mac. The Ethernet Low Level Driver (Enet-LLD) APIs can be used to realize this networking capability using the ICSSG sub-system.

Enet LLD Introduction

ENET ICSSG Examples

Enet Layer 2 ICSSG Example
Enet ICSSG Loopback Example
Enet Lwip ICSSG Example | Enet Lwip TCP Server Example on ICSSG
Enet VLAN ICSSG Example
Enet ICSSG Time Aware Shaper (EST) Example
Ethernet TSN ICSSG gPTP TimeReceiver (gPTP Slave) Example | Ethernet TSN ICSSG gPTP TimeTransmitter (gPTP Master) Example | Ethernet TSN ICSSG gPTP Bridge Example | Ethernet TSN gPTP on ICSSG along with LwIP stack

Queue Usage

The ICSSG Queues used for packet content buffering are elaborated here:
File : {Any of above ENET ICSSG examples} CCS Project > Generated Source > SysConfig > ti_enet_soc.c

ICSSG_SWITCH_PORT_POOL_SIZE :

  • Buffer for the purpose of Forwarding of Frames from Port A to Port B.
  • Size: Configurable ( By default 6KB)
  • Totally 8 such pools are allocated for each of the QoS levels.

ICSSG_SWITCH_HOST_POOL_SIZE:

  • Buffer for the purpose of transmitting frames from the host to Port A or/and Port B.
  • Size: Configurable ( By default 6KB for 1Gbps Support and 3KB for 100Mbps Support)
  • Totally 'n' such pools are allocated for each of the "QoS Level" configured via SysConfig for each of the ports.

ICSSG_SWITCH_HOST_QUEUE_SIZE:

  • Buffer for the purpose of reception of frames from the Port A or/and Port B to the host.
  • Size: Configurable ( By default 8KB for 1Gbps Support and 5KB for 100Mbps sSupport)
  • Totally 2 such pools are allocated for each of the ports.

To reduce number of Pools

ICSSG_SWITCH_PORT_BUFFER_POOL_NUM: The number of ICSSG Port buffer pools is by default defined as 8 (max) to provide a unique Pool for upto 8 QoS levels.

This number can be reduced as per the requirement of the user application, for example 'n' (n = 1 to 8). However, care must be taken to ensure all priorities (PCPs), in case of VLAN-tagging, are mapped to only those 0 to n-1 Queues.

This can be done by using the IOCTL: ENET_MACPORT_IOCTL_SET_EGRESS_QOS_PRI_MAP

For Example if setting ICSSG_SWITCH_PORT_BUFFER_POOL_NUM = 3, Then the available pools will only be 0 ,1, 2. Hence, all the traffic must be directed to only these queues 0 to 2 by using the above IOCTL. Type of mapping is left to the user.

This PCP to Queue mapping can be done via the input argument of the IOCTL ENET_MACPORT_IOCTL_SET_EGRESS_QOS_PRI_MAP.
uint32_t EnetPort_PriorityMap::priorityMap[ENET_PRI_NUM] , where the array index corresponds to the PCP and the value holds the mapped Queue value

PCP(Index) Queue Number = priorityMap[pcp]
0 0
1 0
2 0
3 1
4 1
5 2
6 2
7 2

Sample IOCTL usage: ENET_MACPORT_IOCTL_SET_EGRESS_QOS_PRI_MAP

/* Mapping the PCP to Queue*/
EnetMacPort_SetEgressPriorityMapInArgs SetEgressPriorityMapInArgs;
EnetPort_PriorityMap PriorityMap;
PriorityMap.priorityMap[0] = 0;
PriorityMap.priorityMap[1] = 0;
PriorityMap.priorityMap[2] = 0;
PriorityMap.priorityMap[3] = 1;
PriorityMap.priorityMap[4] = 1;
PriorityMap.priorityMap[5] = 2;
PriorityMap.priorityMap[6] = 2;
PriorityMap.priorityMap[7] = 2;
SetEgressPriorityMapInArgs.macPort = macPortList[i];
SetEgressPriorityMapInArgs.priorityMap = PriorityMap;
ENET_IOCTL_SET_IN_ARGS(&prms, &SetEgressPriorityMapInArgs);
if (status != ENET_SOK)
{
EnetAppUtils_print("EnetApp_enablePorts() failed to set PCP to Q map: %d\r\n", status);
}

API

APIs for PRUICSS

EnetPort_PriorityMap
Priority map.
Definition: enet_mod_port.h:131
PRUICSS_open
PRUICSS_Handle PRUICSS_open(uint32_t index)
This function creates the handle for a PRUICSS instance.
EnetMacPort_SetEgressPriorityMapInArgs::priorityMap
EnetPort_PriorityMap priorityMap
Definition: enet_mod_macport.h:522
PRUICSS_resetCore
int32_t PRUICSS_resetCore(PRUICSS_Handle handle, uint8_t pruNum)
This function resets the PRU.
EnetPort_PriorityMap::priorityMap
uint32_t priorityMap[ENET_PRI_NUM]
Definition: enet_mod_port.h:134
pruicss.h
PRUICSS_enableCore
int32_t PRUICSS_enableCore(PRUICSS_Handle handle, uint8_t pruNum)
This function enables the PRU.
ENET_IOCTL_SET_IN_ARGS
#define ENET_IOCTL_SET_IN_ARGS(prms, in)
Set the input args for an IOCTL command.
Definition: enet_ioctl.h:122
ENET_MACPORT_IOCTL_SET_EGRESS_QOS_PRI_MAP
@ ENET_MACPORT_IOCTL_SET_EGRESS_QOS_PRI_MAP
Set QoS egress priority map.
Definition: enet_mod_macport.h:154
SYS_EVT_POLARITY_HIGH
#define SYS_EVT_POLARITY_HIGH
Definition: icss_intc_defines.h:306
PRUICSS_IRAM_PRU
#define PRUICSS_IRAM_PRU(n)
IRAM for PRU0/PRU1. n = 0 for PRU0,n = 1 for PRU1.
Definition: pruicss/g_v0/pruicss.h:104
ENET_IOCTL
#define ENET_IOCTL(hEnet, coreId, ioctlCmd, prms, status)
Helper macro used to first register IOCTL handler and then invoke the IOCTL.
Definition: enet_ioctl.h:188
PRUICSS_disableCore
int32_t PRUICSS_disableCore(PRUICSS_Handle handle, uint8_t pruNum)
This function disables the PRU.
SYS_EVT_TYPE_PULSE
#define SYS_EVT_TYPE_PULSE
Definition: icss_intc_defines.h:308
EnetMacPort_SetEgressPriorityMapInArgs::macPort
Enet_MacPort macPort
Definition: enet_mod_macport.h:519
SYS_EVT_TYPE_EDGE
#define SYS_EVT_TYPE_EDGE
Definition: icss_intc_defines.h:309
ENET_SOK
#define ENET_SOK
Success.
Definition: enet_types.h:76
EnetMacPort_SetEgressPriorityMapInArgs
Input args for ENET_MACPORT_IOCTL_SET_EGRESS_QOS_PRI_MAP command.
Definition: enet_mod_macport.h:517
DebugP_assert
#define DebugP_assert(expression)
Function to call for assert check.
Definition: DebugP.h:177
PRUICSS_intcInit
int32_t PRUICSS_intcInit(PRUICSS_Handle handle, const PRUICSS_IntcInitData *intcInitData)
This function does Interrupt-Channel-host mapping.
PRUICSS_writeMemory
uint32_t PRUICSS_writeMemory(PRUICSS_Handle handle, uint32_t pruicssMem, uint32_t wordoffset, const uint32_t *source_mem, uint32_t bytelength)
This function writes the given data to PRU memory.
PRUICSS_PRU0
#define PRUICSS_PRU0
Definition: pruicss/g_v0/pruicss.h:74
PRUICSS_registerIrqHandler
int32_t PRUICSS_registerIrqHandler(PRUICSS_Handle handle, uint32_t pruEvtoutNum, int32_t intrNum, int32_t eventNum, uint8_t waitEnable, PRUICSS_IrqHandler irqHandler)
This function registers an Interrupt Handler for an event.