6. Device Drivers

6.1. CSL


Overview

The Chip Support Library constitutes a set of well-defined APIs that abstract low-level details of the underlying SoC device so that a user can configure, control (start/stop, etc.) and have read/write access to peripherals without having to worry about register bit-field details. The CSL services are implemented as distinct modules that correspond with the underlying SoC device modules themselves. By design, CSL APIs follow a consistent style, uniformly across Processor Instruction Set Architecture and are independent of the OS. This helps in improving portability of code written using the CSL.

CSL is realized as twin-layer – a basic register-layer and a more abstracted functional-layer. The lower register layer comprises of a very basic set of macros and type definitions. The upper functional layer comprises of “C” functions that provide an increased degree of abstraction, but intended to provide “directed” control of underlying hardware.

It is important to note that CSL does not manage data-movement over underlying h/w devices. Such functionality is considered a prerogative of a device-driver and serious effort is made to not blur the boundary between device-driver and CSL services in this regard.

CSL does not model the device state machine. However, should there exist a mandatory (hardware dictated) sequence (possibly atomically executed) of register reads/writes to setup the device in chosen “operating modes” as per the device data sheet, then CSL does indeed support services for such operations.

The CSL services are decomposed into modules, each following the twin-layer of abstraction described above. The APIs of each such module are completely orthogonal (one module’s API does not internally call API of another module) and do not allocate memory dynamically from within. This is key to keeping CSL scalable to fit the specific usage scenarios and ease the effort to ROM a CSL based application.

In general for application recommended interfaces to be used will be driver API. CSL Functional layer APIs could be used for low-level access when required. CSL Register layer memory map is available for being used under rare cases in application when required.

The source code of the CSL is located under $(TI_PDK_INSTALL_DIR)\packages\ti\csl directory.

AM335x/AM437x

The CSL component of AM335x/AM437x Processor SDK is referred as StarterWare in the legacy baseline releases.To maintain backward compatibility for existing applications on AM335x/AM437x SOCs, StarterWare low level package is retained. Customers are recommended to use driver interfaces for ease of migration of application software across SOCs.

Chip Support Library/DAL Summary
Component Type Library
Install Package PDK
Install Directory pdk_AMX_<version>\packages\ti\starterware
Endian Support Little
Linker Path PDK_INSTALL_DIR\packages\ti\starterware\binary
Include Paths PDK_INSTALL_DIR\packages\ti\starterware\include

6.1.1. AM57x/K2x/C66x/C674x

6.1.1.1. Application Integration

CSL is common package supporting multiple devices.Software layer using CSL source would need to pass compile time define -DSOC_XXX. Refer ticslsoc.h for list of devices/SOC’s

Refer list of APIs/interfaces available under <PDK_INSTALL_DIR\packages\ti\csl> directory.

Chip Support Library Summary
Component Type Library
Install Package PDK
Install Directory PDK_INSTALL_DIR\packages\ti\csl
Endian Support Little
Linker Path PDK_INSTALL_DIR\packages\ti\csl
Include Paths $(TI_PDK_INSTALL_DIR)\packages\
Reference Guides See docs under Install Directory

6.1.2. CSL-FL EXAMPLES

These are example projects to test the functionality of API in CSL-FL layers. The following is the list of CSL-FL test examples which are supported with the CSL library:

  • DCAN
  • EDMA
  • GPIO
  • MAILBOX
  • I2C
  • QSPI
  • WDTIMER
  • MMCSD
  • MMU
  • SPINLOCK
  • UART
  • ECC : Limited to applicable SOC’s/Boards:idkAM574x

In order build the projects:

  • Navigate to pdk_[soc]_[version]\packages
  • Run pdksetupenv.bat (windows) OR pdksetupenv.sh (linux).
  • Navigate to pdk_[soc]_[version]\packages\ti\csl

All CSL-FL examples can be cleaned and rebuilt with the following commands on windows:

C:\ti\pdk_[soc]_[version]\packages\ti\csl>gmake app_clean
C:\ti\pdk_[soc]_[version]\packages\ti\csl>gmake apps

All CSL-FL examples can be cleaned and rebuilt with the following commands on linux:

~/ti/pdk_[soc]_[version]/packages/ti/csl$ make app_clean
~/ti/pdk_[soc]_[version]/packages/ti/csl$ make apps
  • All the output binary files will be generated in common location i.e. pdk_[soc]_[version]\packages\ti\binary\[EXAMPLE]\bin\[BOARD]\
  • DCAN RTOS example

TI RTOS support is available for CSL DCAN example on AM572x platform. Refer to the readme document at below path for more details.

<PDK Root>/packages/ti/csl/example/dcan/dcanLoopback


6.2. UART

6.2.1. Overview

6.2.1.1. Introduction

Driver enables UART’s available on SOC for reading and writing to any peripherals on board. Additionally it supports simple APIs for Console/STDIO operations.

Modes of Operation

Following modes of operations are supported

UART_MODE_BLOCKING: In this mode, read and write APIs, blocks on semaphore until required operation is complete. By default, UART driver operates in blocking mode. In this mode, code execution of a task blocks until UART transaction is complete. While transaction is in progress additional tasks pending requests will remain in blocked state waiting for semaphore.

UART_MODE_CALLBACK: In this mode, read and write operation returns immediately. On trigger of hardware Interrupt (hwi) callback function gets triggered.

6.2.2. User Interface

6.2.2.1. Driver Configuration

Board Specific Configuration

All board specific configurations eg:enabling clock and pin-mux for UART pins are required before calling any driver APIs.By default Board_Init() API supports all initialization sequence for TI supported EVMs. In addition it initializes UART instance for Console/STDIO.Refer Processor SDK RTOS Board Support for additional details.Once board specific configuration is complete UART_init() API can be called to initialize driver.

UART Configuration Structure

The UART_soc.c file binds driver with hardware attributes on the board through UART_config structure. This structure must be provided to UART driver. It must be initialized before the UART_init() function is called and cannot be changed afterwards. For details about individual fields of this structure, see the Doxygen help by opening PDK_INSTALL_DIRpackagestidrvuartdocsdoxygenhtmlindex.html.

6.2.2.2. APIs

API reference for application:

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

STDIO API reference for application:

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

Open UART

There are three ways to open a UART instance:

  1. UART_open()
...
Board_init(boardCfg);
...
UART_socGetInitCfg(UART_INSTANCE, &uart_cfg);
...
UART_socSetInitCfg(UART_INSTANCE, &uart_cfg);
...
UART_Params_init(&params);
...
handle = UART_open(UART_INSTANCE, &params);

At this point UART driver is ready for data transfer on specific instance identified by handle. Application can call UART_read/write API for read/write operation

  1. UART_stdioInit() using the default UART parameters
...
Board_init(boardCfg);
...
UART_socGetInitCfg(UART_INSTANCE, &uart_cfg);
...
UART_socSetInitCfg(UART_INSTANCE, &uart_cfg);
...
UART_stdioInit(UART_INSTANCE);

At this point UART driver is ready for data transfer on specific instance. Application can call UART_printf/scanFmt API for read/write operation

  1. UART_stdioInit2() using Application specified UART parameters
...
Board_init(boardCfg);
...
UART_socGetInitCfg(UART_INSTANCE, &uart_cfg);
...
UART_socSetInitCfg(UART_INSTANCE, &uart_cfg);
...
UART_Params_init(&params);
...
UART_stdioInit2(UART_INSTANCE, &params);

At this point UART driver is ready for data transfer on specific instance. Application can call UART_printf/scanFmt API for read/write operation

Read/Write APIs

Interrupt:

UART_read(handle,scanPrompt, sizeof(scanPrompt));/* Read API */
...
UART_write(handle, bufferPrompt, sizeof(bufferPrompt));/* Write API */

Or

UART_transactionInit(&transaction);
transaction.buf = (void *)scanPrompt;
transaction.count = sizeof(scanPrompt);
UART_read2(uart, &transaction);
...
UART_transactionInit(&transaction);
transaction.buf = (void *)bufferPrompt;
transaction.count = sizeof(bufferPrompt);
UART_write2(uart, &transaction);

Polling:

UART_readPolling(handle,scanPrompt, sizeof(scanPrompt));/* Read Polling mode API */
...
UART_writePolling(handle, bufferPrompt, sizeof(bufferPrompt));/* Write Polling API */

EDMA Usage :

UART driver supports EDMA operations to transfer data between

  • Memory and RX FIFO for read transfer
  • Memory and TX FIFO for write transfer.

Driver uses separate source files for these operations.Refer source UART_soc_dma.c for DMA UART SOC configuration. Application need to create EDMA handle and update the configuration before UART_init() API.

uartInitCfg[UART_INSTANCE].edmaHandle = UartApp_edmaInit();/* Refer Example/Test */
UART_init();

Refer “UART_BasicExample_[SOC]_[cpu]DMATestproject” for additional reference. Refer SDK Release Note for supported EVMs.

6.2.3. Application

6.2.3.1. Examples

Name Description Expected Results
UART_Example application Example demonstrating simple UART use case. Reference example for developers

Application prompts user to enter input data in console.

User can enter up to 16 characters or terminate with enter key.Application echoes back characters.

UART_TestApplication Unit Test application to test all APIs User can enter up to 16 characters using serial console.Application echoes back
UART_DMATestApplicati on Unit Test application with DMA mode. User can enter up to 16 characters using serial console.Application echoes back

6.2.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)/packages/ti /drv/gpio/docs/doxygen/html/index .html
Release Notes $(TI_PDK_INSTALL_DIR)/packages/ti /drv/gpio/docs/ReleaseNotes_UART _LLD.pdf

6.3. USB

6.3.1. Overview

6.3.1.1. Driver Overview

PDK USB driver (USB LLD) provides the following USB class/functions while isolating application from the complexity of low level USB and USB class protocols:

  • USB device Mass Storage Class
  • USB host Mass Storage Class
  • USB device Audio Class
  • USB generic bulk device class

In rest of the page AM437x EVM is being refered as an example. Please check Release Notes for list of supported EVMs for driver.

Modes of Operation

  • USB device Mass Storage Class
    • USB device Mass Storage Class with RAM DISK

In this mode, a user-selected USB instance of the EVM will be working in device mode and will behave like a USB thumb drive. It uses part of the EVM DDR memory and exposes it as a physical storage for another USB host application. After the host PC enumerates this EVM-thumb drive, the PC will see a USB storage device. This EVM-thumb drive is not yet formatted with any file system and requires user to format it before use.

../_images/USB_MSC_device.PNG

The following screen shots show what one would expect when running the device mode demo application and plugging in a USB cable from the EVM USB port #0 to a PC running Windows

Printout from demo application:

../_images/Device_mode_printout.png

The MSC device is detected in Windows, and a FAT formatted USB drive named “PDK-USBDEV” should be seen in the “Window Explorer”. The content of the drive is just a readme.txt file. This USB drive can be manipulated like any other removable USB drive.

../_images/Windows_pdk_usb.png

Windows might show a message saying it should be scanned and fixed. We can just ignore it and just continue without scanning.


  • USB device Mass Storage Class with MMCSD card

This example acts like a USB - MMCSD card reader. The example exposes the EVM’s MMCSD card to the Host PC via USB MSC. The Host PC can manipulate files on the attached MMCSD card on the EVM. This example is currently supported on AM335GP EVM. This is how it looks. Its code is similar to that of the USB device MSC example but with the call back functions calling MMCSD API’s instead of RamDisk APIs

../_images/Usb_device_mmcsd.PNG

  • USB host Mass Storage Class

In this mode, the USB instance will act as a USB host communicating with a USB device that supports Mass Storage Class function (USB thumb drive or a small USB hard drive). The demo example code utilizes a shell interface via the EVM via UART for interaction with the example. The shell provides some basic commands to manipulate the content of the attached USB disk drive.

../_images/USB_MSC_host.PNG

Screenshot of a MSC host mode example running in RTOS after plugging in a USB thumb drive into USB port #1

../_images/Host_shell_screen_shot.png

  • USB device Audio Class

In this mode, USB instance of the EVM will be working in device mode and will behave like a USB headset with MIC. It uses audio codec on the EVM for running playback and record initiated by the USB host. McASP module will be used to transfer the data between USB device and audio codec on the board. EVM will appear as a new USB audio device on the host PC. Changing the default audio device on the host PC to EVM USB device will allow the playback and record operations between EVM and USB host. This mode of operation is currently supported on AM335X GP EVM, OMAP-L137 EVM and OMAP-L138 LCDK.


../_images/Am335x_usb_ac_bd.jpg

  • USB generic bulk device class

In this mode, a user-selected USB instance of the EVM will be working in device mode. The mentioned USB device will show up in the host PC as a generic USB bulk device with one single interface containing a bulk IN and a bulk OUT endpoints. The configuration and interface descriptors published by the device contain vendor-specific class identifiers, so an application on the host will have to communicate with the device using either a custom driver or a subsystem such as WinUSB or libusb-win32 on Windows (or just libusb on Linux) to read and write to the device.

  • Running USB bulk device demo application

The bulk demo application requires a host PC with USB host plugged to the USB device port on the EVM. Depending on the platform, the USB device port might be USB port #0 or #1.

../_images/USB_MSC_device.PNG

Please refer to PDK user guide for how to generate USB example projects. Once the demo application is loaded and run, the EVM UART console shows the following:

../_images/usb_dev_bulk_console.png

A Python host PC example application is provided in ti/drv/usb/example/usb_dev/bulk/usb_dev_bulk_host_application.py


The example Python script requires PyUSB to run. On Linux host, proper UDEV rule is also required in order to access the USB bulk device as non-sudo user. The script itself also lists the requirements to run it as well as what command options available. The example UDEV rule is also placed in the same place where the Python script is located. It does the following:

  • The Python script looks for the USB device with the example PID:VID,
  • Sends an ASCII text string to the USB bulk demo application running on the EVM
  • Expects the same text string with reversed case letter returned back, and also
  • Verifies the received data with the data that it has sent and report the test result.

A screen shot of what the Python test script outputs

../_images/usb_dev_bulk_host_tool_output.png

The USB bulk demo application configures the USB endpoints as high speed endpoints with 512KB packet size.



6.3.2. User Interface

6.3.2.1. Driver Configuration

  • Data Structures:
    • tUSBDMSCDevice: Defined in usbdmsc.h. It is used in USB device mode application. This structure must be filled with the intended vendor and product ID as well as other product information and also the function pointers to functions that handle the disk functions (open/read/write/close, etc.). These product information will show up in the device and interface USB descriptors that are used during device enumeration. This device MSC class data is then assigned to the field usbClassData of the USB_Params bellow.
    • USB params: USB_Params structure is declared in usb_drv.h. This structure must be provided to the USB driver. It must be initialized before the USB_open() function is called.
    • USB APIs: main USB LLD and USB MSC API’s are declared in usb_drv.h and usbdmsc.h and usbhmsc.h provided in the root USB LLD directory.

  • General USB LLD expectations:

The USB LLD will setup appropriate USB clock and power domains for the particular SOC being in used as part of its “device specific peripheral” functions.

After the USB_open() is called, the driver expects the application code to sets up USB interrupts with the interrupt handler being the USB LLD provided interrupt handler. Then the application have to call the USB LLD provided API USB_irqConfig() which enables USB module’s interrupts. In device mode, both USB core and USB misc interrupts are used in the USB device MSC application. In host mode, the USB host MSC only uses USB core interrupts.

After these steps, application code then can expect to have USB enumeration done and start USB transfer through the provided APIs.

6.3.2.2. API Call Flow

  • USB Device MSC

The example application code uses the USB library, configures it as a USB device with MSC function. The example also provides functional codes that access a RAM disk (included from the Utils library in the included Starterware). The LLD calls these MSC back-ends functions to access the RAM disk. User can replace these functions with other functions that access other types of media or devices (MMCSD for example). The RAM disk image provided in the example demo application is not currently formatted. Thus the once enumerated, the PC will require the USB disc to be formatted before use.

Below diagram is the sequence of API calls that starts the USB device MSC application. All USB events are handled internally in the LLD and in the interrupt context.

../_images/USB_MSC_device_API_flow.PNG

User provided disk functions will be called from the LLD to handle the actual physical disk access. The overview of USB Device MSC example application:

../_images/USB_MSC_device_example_blocks.PNG

The content of the file: usb_msc_structs.c can be replaced with customer USB device information (PID/VID, device names, etc.)

  • USB Host MSC

The LLD also provides a USB host MSC example. The USB LLD is acting as a USB host, waiting for a USB thumb drive/memory stick to be plugged in. A console with a simple shell command is also provided so that the demo example can display and manipulated content of the USB device.

The following is how the USB host MSC example demo is organized:

../_images/USB_MSC_host_example_blocks.PNG

The following is the sequence of the APIs that were used:

../_images/USB_MSC_host_API_flow.PNG

  • USB Device Audio

The example application code uses the USB library, configures it as a USB device with Audio class function. USB LLD along with the application enumerates as the USB audio class device and allows accessing the audio ports on the EVM from USB host. It supports audio playback and record operations.

Below diagram is the sequence of API calls that starts the USB device audio application. All USB events are handled internally in the LLD and in the interrupt context.

../_images/USB_Audio_class_flowchart.jpg

  • USB Device Bulk

Sequence of API calls as long as what the example application looks like are described bellow

../_images/usb_device_generic_bulk_example_application.png
  • Main APIs that are used to read/write from and to the USB bulk device are USBD_bulkRead() and USBD_bulkWrite().

These two functions will block the caller until they finish their operation.

  • The main application should wait for about 500ms after the USB host sends the SetConfig request to make sure

the enumeration is completely finished before calling USBD_bulkRead/Write functions

6.3.3. Application

6.3.3.1. Examples

Bare-metal and RTOS/BIOS examples of the USB device and USB host MSC are provided with the USB LLD. RTOS/BIOS examples are provided for USB device audio class. Please see the readme.txt in the docs directory for more info on how to build the example/demo application. Refer SDK release notes for supported EVMs.

Example Name EVM’s supported Notes
usb_dev_msc_mmcsd AM335GP EVM  
usb_dev_msc AM335GP, AM437xGP, AM57xIDK, AM572GP EVM, K2G EVM, OMAP137EVM, OMAPL138LCDK OMAPL13 LCDK host and device examples share the same USB port.
usb_host_msc AM335GP, AM437xGP, AM57xIDK, K2G EVM, OMAP137EVM, OMAPL138LCDK OMAPL13 LCDK host and device examples share the same USB port. Need OTG cable for EVM with OTG port to work in host mode. USB3.0 host supported on AM572IDK.
usb_device_audio AM335xGP,OMAPL137 EVM,OMAPL138 LCDK Refer to Hardware Setup and How to Run the Demo sections below
usb_device_bulk AM335xGP, AM437xGP, AM572xIDK, AM571xIDK, AM574xIDK, K2GEVM  

6.3.4. Hardware Setup

This section provides the specific HW setup required to run the USB examples.


  • USB Device Audio

USB audio class demo requires additional setup for running playback and record operations. Below sections provide the setup details for each platform supported.


AM335x GP EVM

../_images/Am335x_usb_ac_setup.jpg

OMAPL137 EVM

../_images/Omapl137_usb_ac_setup.jpg

OMAPL138 LCDK

../_images/Omapl138_usb_ac_setup.jpg

How to Run the Demo

  • Follow this link Processor SDK RTOS Setup CCS to get target configuration setup correctly.
  • Use CCS to import the USB_DevAudio_<board>_<core>ExampleProject under pdk_<platform>_<version>/packages/MyExampleProjects.
  • Build the imported project. the OUT file will be at pdk_<platform>_<version>/packages/MyExampleProjects/USB_DevAudio_<board>_<core>ExampleProject/Debug.
  • Make the HW connections as shown in Hardware Setup section
  • Launch the target configuration for the EVM from CCS 7.x.
  • Connect to ARM or DSP core as applicable.
  • Load the pdk_<platform>_<version>/packages/MyExampleProjects/USB_DevAudio_<board>_<core>ExampleProject/Debug/USB_DevAudio_<board>_armExampleProject.out.
  • Run the program (loaded previously) by pressing F8
  • The CCS ConsoleIO will display the following:
../_images/CCS_console_output.png
  • Right click on the “Speaker Icon” on the USB Host (right side of the toolbar), then select “Playback devices”
  • Wait until the “Speakers USB Audio Device” shows up in the “Sound” dialog
../_images/Sound.png
  • Select the “Speakers USB Audio Device” in the “Sound” dialog, then click the “Configure”
../_images/Speaker_setup.png
  • Click the “Test” in “Speaker Setup”, you should hear the testing tone in the headphone connected to the EVM

Note

‘board’ can be evmAM335x, evmOMAPL137 or lcdkOMAPL138

‘core’ can be arm or c674x

6.4. PCIe

6.4.1. Overview

PCIe module supports dual operation mode: End Point (EP or Type0) or Root Complex (RC or Type1). This driver focuses on EP mode but it also provides access to some basic RC configuration/functionality. For RC this is the lowest level; additional software is needed to perform generic enumeration of third party devices.

The PCIe subsystem has two address spaces. The first (Address Space 0) is dedicated for local application registers, local configuration accesses and remote configuration accesses. The second (Address Space 1) is dedicated for data transfer. This PCIe driver focuses on configuration of the interface and sending/receiving interrupts via Address Space 0. Data is transferred outside the scope of the LLD using CPU or EDMA through the data area.

There are two revisions of the pcie hardware. The first, v0, in KeyStone devices (C66x, K2x). The second, v1, is in AM57xx devices. The LLD abstacts the configuration of standards-based PCIe registers (Type 0, Type 1 and Capabilities registers) so same user code can be used on both device types. However, there are different interfaces for the registers not based on PCIe standards (port logic and ti-conf which generally covers interrupts and address translation). That portion of user code needs to differ between C66x/K2x and AM57xx devices.

The example includes configuration of one SoC as EP and a second as RC. It then performs a simple CPU-based memory transfer (EDMA can be used via the same addresses used by the CPU), and interrupt generation (from EP) and reception (to RC). It also shows differences in user code required to support both C66x/K2x and AM57xx devices.

Differences in Operation between C66x/K2x and AM57xx devices

C66x/K2x and AM57xx are functionally identical, except that interrupts are handled by example and lld only on AM57xx.

Modes of Operation

The LLD is intended to bring up the PCIe peripheral, open memory mappings, and send/receive interrupts.

Root Complex (RC)

The PCIe peripheral can be used as a root complex. One or more other endpoints can be connected (more than one requires a PCIe switch on the board). The LLD configures the peripheral in RC mode. It doesn’t attempt to emulate the full enumeration capability of a Linux driver. Instead the user will need to supply code specific to each endpoint they intend to support.

Endpoint (EP)

The PCIe peripheral can be used as an endpoint. This is the more intended usecase for the LLD. Once the link is initialized, the LLD can provide data addresses and send interrupts to the RC.

Interrupts

The example for AM57XX provides code to send interrupts from an endpoint, and the LLD/example together contain code to receive/demux the interrupts (both MSI and Legacy) on an RC.

6.4.2. User Interface

6.4.2.1. Driver Configuration

Board-specific configuration

PCIe’s board specific configuration is in the example in PDK_INSTALL_DIR/packages/ti/drv/pcie/example/sample/am57x/src/pcie_sample_board.c. Calling sequence is in example and repeated below.

PCIe configuration structure

The pcie_soc.c binds the driver to the hardware on the board. It is passed into the driver via the call to Pcie_init().

6.4.2.2. API Call Flow

The API call flow is covered in pcie_sample.c.

The overall components are:

  1. Initialize the driver
  2. Initialize the SERDES and Power the peripheral (see example code for order for each device)
  3. Configure RC or EP symmetrically to talk to another similar device
  4. Perform data IO and interrupt.

6.4.3. Application

6.4.3.1. Examples

Name Description EVM Configuration Expected Results
PCIE_idkAM57[12 4]x*ExampleProj ect 2-device PCIe connection

IMPORTANT: Cable must be MODIFIED in order to avoid damaging the clock drivers in the SoC!

Connect two like AM57xx IDK EVMs J22 MODIFIED male-male crossover PCIe x1 or x4 cable and optional straight-through extender. For AM572x/AM574x we used a one-lane cross cable; for AM571x we used a 4-lane cross cable. | Projects available for C66, A15, and M4.

AM572x/AM574x or AM571x EVM : One board is EP/other is RC; link is established and data/interrupts exchanged. All printed output goes to the serial console.
PCIE_evmK2G*Exa mpleProject 2-device PCIe connection

IMPORTANT: Cable must be MODIFIED in order to avoid damaging the clock drivers in the SoC!

Connect two K2G  EVMs J5 using a MODIFIED male-male crossover PCIe x1 cable and optional straight-through extender. We used a one-lane cross cable. Ensure that jumper J15 is positioned to the left hand two pins as viewed with “J15” silkscreen right side up (pin 0 isn’t clearly marked). In the right hand position, the PCIe PLL will NOT get clock. Projects available for C66 and A15.

K2G EVM : One board is EP/other is RC; link is established and data is exchanged. All printed output goes to serial console.
PCIE_idkAM571x_* armEdmaPktExam pleProject (Available starting in Processor-SDK 3.1) Packet Exchange over PCIe Benchmark

IMPORTANT: Cable must be MODIFIED in order to avoid damaging the clock drivers in the SoC!

Connect two like >=REV1.3A AM571x  IDK EVMs J22 using a MODIFIED male-male crossover PCIe x4 cable and optional straight-through extender. We used a 4-lane cross cable. Projects available for A15 only. >=REV1.3A EVM required (for x4 PCIe connectors).

AM571X >=REV1.3A IDK : One board is EP/other is RC; link is established and data is exchanged. Produces same output as standard ExampleProject, except EP also prints packet exchange benchmark results.
Remaining PCIE_*ExamplePr oject 2-device PCIe connection Connect two like C66x/K2x (except K2G, see previous row) EVMs using an AMC breakout card. For K2L, it is necessary to configure the mux via the BMC console with “interface_muxs el pcie” command. Projects available for A15 and/or C66 as present in each device. 6678, 6657, K2E, K2H, K2L : One board is EP/other is RC; link is established and data exchanged. For A15 projects, all printed output goes to serial console. For C66 projects, all printed output goes to CCS console.

Quick setup of xds100 for two EVMs

  1. create new target configuration using XDS100v2 and AM572x (or AM571x) from the basic tab.
  2. Select Advanced tab.
  3. Highlight the XDS100v2, and click the “new” button and add second XDS100v2.
  4. Highlight the newly added XDS100v2, click the “add” button and select a second Am572x.
  5. open command prompt, and run ticcs_basecommonuscifxds100serial to get your serial numbers
  6. Highlight first XDS100v2, select “Debug Probe Selection” to “Select by Serial number” and enter one of the 2 serial numbers
  7. Repeat second XDS100v2, setting to to the second serial number.

General instructions for configuring multiple EVMs with any emulator type are available in Multi-Emulator_Debug_with_CCS

Detailed instructions to run example

Ensure 2 Like EVMs are connected with a x1 PCIe male/male cross cable (for AM5XX) or a breakout card (for C667x, C665x, K2x)

Build project(s) appropriate for your EVM. Projects for A15 and C66 are provided based on core types available on each device.

Load via jtag either the ARM or DSP projects (but don’t mix and match) onto the first arm or dsp core of each the 2 EVMs. Same .out file supports both RC and EP. Use an “expressions” window to set PcieModeGbl to PCIE_RC_MODE on one EVM (it makes that EVM RC). Leave the second EVM alone (pcie_EP_MODE). Run the loaded cores. See table above to determine whether output is expected on serial console or CCS console.

Sample example output

Note that output will vary slightly based on device type. The following is from A57XX. The output from the RC and EP are interleaved since this is run from a 2*XDS1000 double config as described in #Quick setup of xds100 for two EVMs

**********************************************
*             PCIe Test Start                *
*                RC mode                     *
**********************************************

Version #: 0x02020003; string PCIE LLD Revision: 02.02.00.03:Dec 24 2015:17:38:37

PCIe Power Up.
PLL configured.
Successfully configured Inbound Translation!
Successfully configured Outbound Translation!
Starting link training...
**********************************************
*             PCIe Test Start                *
*                EP mode                     *
**********************************************

Version #: 0x02020003; string PCIE LLD Revision: 02.02.00.03:Dec 24 2015:17:38:37

PCIe Power Up.
PLL configured.
Successfully configured Inbound Translation!
Successfully configured Outbound Translation!
Starting link training...
Link is up.
Link is up.
End Point received data.
End Point sent data to Root Complex, completing the loopback.
EP sending interrupts to RC
Root Complex received data.
RC waiting for 10 of each of 2 types of interrupts
RC got all 20 interrupts
Test passed.
End of Test.

6.4.4. Debug FAQ

  1. If example fails to get link up
    1. Confirm that male/male cross cable or breakout board is correctly connected.
    2. If running from ARM cores, confirm that immediately after reset/reload that both devices have PcieModeGbl=PCIE_EP_MODE. If the PCIE_RC_MODE seems to survive reset/reload, it seems to mean watch window failed to refresh. Click the “Refresh” button for the watch window and it should flip back to EP, where you can reset it to RC. Simply running will cause both sides to run as EP, which leads to test failure.
    3. Confirm that one side of the example has PcieModeGbl=PCIE_RC_MODE and the other is PCIE_EP_MODE.
      1. Note that when changing to RC you must click somewhere outside the expression value to make the modification for RC to “take effect”. Simply pressing F8 after modifying the value will run without actually modifying the variable! The modification will be done when the ARM or DSP is stopped, so everything looks right, except that the log will show “PCIe test start EP mode” twice instead of “PCIe test start EP mode” once and “PCIe test start RC mode” once.

6.4.5. Additional References

Additional documentation can be found in:

Document Location
Hardware Peripheral Users Guide
  • C66x/K2x: User Guide
  • AM57XX: TRM Chapter 24.9 titled “PCIe Controller”
API Reference Manual $(TI_PDK_INSTALL_DIR)/packages/ti /drv/pcie/docs/doxygen/html/index .html
Release Notes $(TI_PDK_INSTALL_DIR)/packages/ti /drv/pcie/docs/ReleaseNotes_PCIE_LLD.pdf

6.5. GPIO

6.5.1. Overview

6.5.1.1. Introduction

GPIO module allows application to manage General Purpose I/O  instances and pins via simple portable APIs. Because of its simplicity, APIs are pin based and does not follow model of other drivers inside PDK which requires handle abstraction.

Modes of Operation

Following modes of operations are supported Input or Output Each gpio pin can be configured as either input: GPIO_CFG_INPUT or output: GPIO_CFG_OUTPUT. If it is configured as an output then pin level can be additionally configured

Interrupt support Each gpio pin can be configured to generate interrupts based on event type GPIO_CFG_IN_INT_XXX configuration. To generate interrupt, gpio pin has to be configured as input pin.

Driver Configuration

Board Specific Configuration

All board specific configurations like enabling clock and pin-mux are required before calling any driver APIs. By default Board_Init() API available under board module supports all initialization sequence for TI supported EVMs. In addition it initializes UART instance for Console/STDIO. Refer Processor SDK RTOS Board Support for additional details.

GPIO Configuration Structure

GPIO_soc.c binds driver with hardware attributes on the board. Hardware attributes includes base address, interrupt number etc. GPIO pin behavior can be configured statically, or alternatively dynamically during runtime.

GPIO_init () API triggers all static configuration information available through hardware attributes. Once initialization is complete additional APIs can be used to configure and access pins.

6.5.1.2. APIs

API reference for Application:

#include <ti/drv/gpio/GPIO.h>

Below sequence indicates API calling sequence for a simple use case of LED toggling

...
Board_init(boardCfg);
GPIO_init();
While(1)
{
GPIO_write(Board_LED1, GPIO_PIN_VAL_HIGH);
Delay();
GPIO_write(Board_LED1, GPIO_PIN_VAL_LOW);
Delay();
}

6.5.2. Application

6.5.2.1. Examples

Refer SDK Release Note for GPIO support across different EVMs.

Name Description
Expected Results
GPIO_LedBlink Simple example demonstrating LED Toggling
Following LED blinks based on EVM being used.
AM335x ICEv2: USER  LED 1
AM437x EVM: USER  LED 1
AM572x IDK : STATUS LED 1 Yellow AM572x GP EVM : USER LED1 AM574x IDK : STATUS LED 1 Yellow AM572x GP EVM : USER LED1 AM571x IDK : Industrial LED 3 Red
K2H EVM: USER LED 2 Blue
K2E EVM: USER LED 1 Blue
K2G EVM: USER LED 1 Yellow

Note

There are no user mode LEDs directly connected to GPIO pins on K2L, C6678 and C6657 EVMs.

6.5.3. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)/packages/ti /drv/gpio/docs/doxygen/html/index .html
Release Notes $(TI_PDK_INSTALL_DIR)/packages/ti /drv/gpio/docs/ReleaseNotes_GPIO _LLD.pdf

6.6. I2C

6.6.1. Overview

6.6.1.1. Introduction

I2C module provides an interface to any I2C-bus-compatible device accessible via I2C serial bus. External components attached to I2C bus can serially transmit/receive data to/from the CPU through two-wire interface. Driver supports three types of transfers in both I2C master mode and slave mode

  • Read
  • Write
  • Write followed by read

In addition driver supports following modes of operation:

  • I2C_MODE_BLOCKING: By default, driver operates in blocking mode. In blocking mode, a Task’s code execution is blocked until transaction is complete. This ensures only one transaction operates at a given time. Driver supports both interrupt or non-interrupt based blocking modes.
  • I2C_MODE_CALLBACK In callback mode, an I2C transaction functions asynchronously, which means that it does not block a Task’s code execution. After an I2C transaction is complete, I2C driver calls a user-provided hook function. Only interrupt based callback is supported.

Note

If I2C peripheral is in reset during a transfer, it can cause the I2C bus to hang. I2C V0 IP (Keystone SoCs) does not have hardware support to recover the I2C bus from hanging, user needs to power cycle the board as a workaround. For I2C V1 IP (AM3/4/5 SoCs), the application can call I2C_control() API and use I2C_CMD_RECOVER_BUS to recover the I2C bus.

Firmware

TI PRU-ICSS cores (Programmable Real-Time Unit Industrial Communication Subsystem) is firmware programmable and can take on various personalities. Processor SDK package includes I2C Firmware support. Refer I2C FW for additional details.


6.6.2. User Interface

6.6.2.1. Driver Configuration

Board Specific Configuration

All the board specific configurations eg:enabling and pin-mux of I2C pins should be performed before calling any driver APIs.By default Board_Init() API supports all initialization sequence for TI supported EVMs.Refer Processor SDK RTOS Board Support for additional details.

Once the board specific configuration is complete driver API I2C_init() can be called to initialize driver

I2C Configuration Structure

I2C_soc.c file binds driver with hardware attributes on the board through I2C_config structure. This structure must be provided to I2C driver. It must be initialized before the I2C_init() function is called and cannot be changed afterwards. For details about the individual fields of this structure, see the Doxygen help by opening PDK_INSTALL_DIR\packages\ti\drv\i2c\docs\doxygen\html\index.html.

6.6.2.2. APIs

API reference for application:

#include <ti/drv/i2c/I2C.h>

 Sample code for initiating I2C transaction:

...
Board_init(boardCfg);
...
I2C_socGetInitCfg(peripheralNum, &i2c_cfg);
...
I2C_socSetInitCfg(peripheralNum, &i2c_cfg);
...
i2c = I2C_open(peripheralNum, &i2cParams);
...
...

/* Initiate I2C transfers. Refer Example for details
*/
I2C_transactionInit(&i2cTransaction);
transaction.masterMode   = true;
...
...
transferOK = I2C_transfer(i2c, &i2cTransaction);
if (transferOK != I2C_STS_SUCCESS) {
/* I2C transaction failed */
}

6.6.3. Application

6.6.3.1. Examples

Refer Release Note for I2C support across different EVMs

Name
Description
Expected Results
I2C_EepromRead Example application
Simple example to read fixed number of bytes from EEPROM on board and compares it with expected data.
Following prints will come on console based on pass/fail criteria:

Pass criteria:

EEPROM data matched All tests have passed.
I2C_TestApplication
Driver Unit Test application for additional I2C speed
Following prints will come on console based on pass/fail criteria:

Pass criteria:

I2C Test: 400Kbps: PASS

I2C Test: 100Kbps: PASS

All tests have passed.
I2C_TemperatureSensor
Example to get the temperature value from the temperature sensor and displays on the serial console.
Following prints will come on console based on pass/fail criteria:

Pass criteria:

Temperature = “value in centigrades” C All tests have passed.
I2C_master/slave
Application demonstrates master/slave transfer of I2C. Application use case requires two EVMs. One acts as Master and the other as slave. I2C connections information and addtional details are as follows:

AM57xx boards I2C bus connection on J9 (master board <–> slave board)

pin22 (SCL)<–> pin22 (SCL)

pin24 (SDA)<–> pin24 (SDA)

pin21 (GND)<–> pin21 (GND)

K2G boards I2C bus connection on J12 (master board <–> slave board) pin28 (SCL)<–> pin28 (SCL) pin30 (SDA)<–> pin30 (SDA) pin50 (GND)<–> pin50 (GND)

OMAPL138/C6748 boards I2C bus connection on J15 (master board <–> slave board) pin13 (SCL)<–> pin13 (SCL) pin15 (SDA)<–> pin15 (SDA) pin35 (GND)<–> pin35 (GND)

Run “I2C_Slave_<BoardTy pe>_<arm/c66x/m4>Test Project” first on Slave EVM and then “I2C_Master_<BoardT ype>_<arm/c66x/m4>Tes tProject” on Master EVM.
Following prints will come on console based on pass/fail criteria:

Pass criteria:

All tests have passed.

Note

I2C_Test Application supports write test on Keystone II EVMs, by default write test is disabled, user can enable the write test by defining I2C_EEPROM_WRITE_ENABLE in test/eeprom_read/src/I2C_board.h. I2C_TemperatureSensor Application is supported only on AM572x GP EVM.

6.6.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\i2c\docs\doxygen\html\index. html
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \drv\i2c\docs\ReleaseNotes_I2C_LL D.pdf

6.7. QSPI-McSPI

SPI driver enables communication for general SPI, MCSPI (Multichannel SPI) and QSPI (Quad SPI) based peripherals on board through common API to application. MCSPI is a generic full-duplex interface supporting transmit and receive of data over SPI bus. QSPI a variant of SPI supports four receive data lanes. Driver supports configuration for either single, dual or quad data lanes

Following modes of operations are supported:

SPI_MODE_BLOCKING SPI_transfer() API blocks code execution until transaction has completed. By default, SPI driver operates in blocking mode. This ensures only one SPI transaction operates at a given time. This mode is supported in both interrupt or non-interrupt configurations.

SPI_MODE_CALLBACK SPI_transfer() API returns without waiting for completion of transaction in this case. Callback function registered by application is invoked once transaction is complete.This mode is supported only in interrupt configuration.

6.7.1. Board Specific Configuration

All board specific configurations eg:enabling clock and pin-mux for SPI pins are required before calling any driver APIs.By default Board_Init() API supports all initialization sequence for TI supported EVMs. In addition it initializes UART instance for Console/STDIO.Refer Processor SDK RTOS Board Support for additional details.Once board specific configuration is complete SPI_init() API should be called to initialize driver.

6.7.2. SoC Specific Configuration

All SoC specific configurations (eg: SPI module registers base address, interrupt configurations, etc.) can be set using SPI_socSetInitCfg() SoC driver API before calling any SPI driver APIs. The default SoC specific configurations can be retrieved using SPI_socGetInitCfg() SoC driver API.

6.7.3. SPI Configuration Structure

The SPI_soc.c file binds driver with hardware attributes on the board through SPI_config[] structure. This structure must be provided to the SPI driver. It must be initialized before the SPI_init() function is called and cannot be changed afterwards. For details about individual fields of this structure, see Doxygen help by opening PDK_INSTALL_DIRpackagestidrvspidocsdoxygenhtmlindex.html.

Driver  requires common SPI_config[]  to configure hardware attributes of MCSPI and QSPI peripherals on SOC and board. First all MCSPI related hardware attributes is defined  followed by QSPI hardware attributes. Application will need to include appropriate offset to instance while invoking SPI_open() API..

API Reference for application:

#include <ti/drv/spi/SPI.h>

SPI IP V1 driver also supports multi-channel API’s:

#include <ti/drv/spi/MCSPI.h>

6.7.4. Open SPI

...
Board_init(boardCfg);
...
SPI_socGetInitCfg(peripheralNum, &spi_cfg);
...
SPI_socSetInitCfg(peripheralNum, &spi_cfg);
SPI_Params_init(&spiParams);
spiParams.transferMode = SPI_MODE_BLOCKING;
spiParams.transferCallbackFxn = NULL;
handle = SPI_open(peripheralNum, &spiParams);

SPI IP V1 driver also supports multi-channel open API’s:

...
Board_init(boardCfg);
...
MCSPI_Params_init(&spiParams);
spiParams.transferMode = SPI_MODE_BLOCKING;
spiParams.transferCallbackFxn = NULL;
handle = MCSPI_open(peripheralNum, channel, &spiParams);

At this point SPI driver is ready for data transfer in blocking mode on specific instance identified by handle. Pseudo/Sample code for SPI read/write transaction is included below. Refer example for additional details

...
spiTransaction.count = n;    /* Transfer Length */
spiTransaction. txBuf = transmitBuffer; /* Buffer to be written */
spiTransaction.rxBuf = NULL;  /* Buffer holding the received data */
transferOK = SPI_transfer(spi, &spiTransaction); /* Perform SPI transfer */
if (!transferOK) {
/* SPI transaction failed */
}

SPI IP V1 driver also supports multi-channel transfer API’s:

...
spiTransaction.count = n;    /* Transfer Length */
spiTransaction. txBuf = transmitBuffer; /* Buffer to be written */
spiTransaction.rxBuf = NULL;  /* Buffer holding the received data */
transferOK = MCSPI_transfer(spi, &spiTransaction); /* Perform SPI transfer */
if (!transferOK) {
/* SPI transaction failed */
}

Note

SPI_open API supports configuration of data word length in the SPI_Params. Currently IP V1 driver (for AM3/4/5 devices) supports 8/16/32-bit word length, IP V0 driver (for Keystone devices) supports 8/16-bit word length.

6.7.5. SPI

Name Description Expected Results

SPI_FlashReadWrite

Example application

Sample application demonstrating read and write of data to a NOR flash device connected over SPI interface. By default, write test is disabled, user can enable write test by defining TEST_SPI_NOR_WRITE in test/src/SPI_board.h

If write test is enabled, write transaction is verified for correctness by reading contents back.

Following prints on console expected: Pass criteria:

All tests have passed.

SPI_TestApplication Driver unit test application to validate features and interfaces for SPI driver Following prints on console expected: Pass criteria: All tests have passed.
spiLoopback example

Example application to validate features and interfaces for SPI driver in loopback mode. Configures the SPI in loopback mode, transmits a test pattern and receives it back from SPI.

Note: This example is intended to demonstrate the SPI LLD API usage on the HW platforms where SPI memory is not available. Currently this example is supported on OMAPL138/C6748 platforms.

Following prints on console expected: Pass criteria: All tests have passed.

6.7.6. QSPI

Name Description Expected Results

QSPI_FlashReadWrite

Example application

Sample application demonstrating read and write of data to a flash device connected over QSPI interface. Write transaction is verified  for correctness by reading contents back.

Following prints on console expected: Pass criteria:

All tests have passed.

QSPI_TestApplication Driver unit test application to validate features and interfaces for QSPI driver Following prints on console expected: Pass criteria: All tests have passed.

6.7.7. MCSPI

Name Description Additional EVM Configuration Expected Results
MCSPI_Serialize r Example application Sample Application demonstrating reading data generated from industrial input module. Application uses GPIO pins to assert load signal in order to generate date from industrial input module.

AM57x IDK EVM:

Short pins 1 and 2 on header J37(Industrial I/O)

AM335x ICE v2: Short pins 1 and 2 on header J14(Industrial I/O)

AM437x IDK EVM: Short pins 1 and 2 on header J1(Industrial I/O)


 

Following prints  on console expected:

Pass criteria:

All tests have passed.

MCSPI_Dma_Seria lizer Example application Sample Application demonstrating reading data generated from industrial input module through EDMA. Application uses GPIO pins to assert load signal in order to generate date from industrial input module. AM57x IDK EVM: Short pins 1 and 2 on header J37(Industrial I/O) | AM437x IDK EVM: Short pins 1 and 2 on header J1(Industrial I/O)

 

Following prints  on console expected:

Pass criteria:

All tests have passed.

MCSPI_SerialFla sh Sample Application demonstrating writing and reading data from the serial flash through MCSPI EDMA interface.

AM335x GP EVM: Set the EVM in profile 2 (SW8[1] = OFF,

SW8[2] = ON, SW8[3:4] = OFF)

 

Following prints  on console expected:

Pass criteria:

All tests have passed.

MCSPI_slavemode example application

Application demonstrates slave recieve and transmit features of McSPI. Application use case requires two EVMs. One acts as Master and Another as slave. McSPI connections information and addtional details are as follows.

No of Boards Required:

2

Connection requirements:

Consider EVM1 as Master and EVM2 as slave.
MasterSPI_CLK ——-SlaveS

PI_CLK | MasterSPI_D0- ———SlaveS PI_D1 | MasterSPI_D1- ———Slave

SPI_D0
MasterSPI_CS0

——–SlaveSP I_CS0 | DGND——— ————-DG ND

Additional Requirements:

Run “MCSPI_SlaveMod e_SlaveExample_ <BoardType><arm /c66x/m4>Exampl eProject” first on Slave EVM and then “MCSPI_SlaveMode _MasterExample <BoardType>_<ar m/c66x/m4>Examp leProject” on Master EVM.


Note:

A DGND connection may be required from expansion connector on each board to make sure the data transfer is proper.

Pin Connections:

IDK AM571x,
IDK AM572x or IDK AM574x:
EVM1(master) ==== EVM2(slave)
J21-Pin24(CLK)—J21-Pin24(CLK)
J21-Pin26(MISO)—J21-Pin28(MISO)
J21-Pin28(MOSI)—J21-Pin26(MOSI)
J21-Pin30(CS)——J21-Pin30(CS)
J21-Pin22(DGND)–J21-Pin22(DGND)

IDK AM437x:
EVM1(master) ==== EVM2(slave)
J16-Pin24(CLK)—–J16-Pin24(CLK)
J16-Pin26(MISO)—J16-Pin28(MISO)
J16-Pin28(MOSI)—J16-Pin26(MOSI)
J16-Pin30(CS)——J16-Pin30(CS)
J16-Pin22(DGND)–J16-Pin22(DGND)

ICEv2AM335x:
EVM1(master) ========= EVM2(slave)
J3-Pin12(CLK)———J3-Pin12(CLK)
J3-Pin14(MIS0)——-J3-Pin16(MISO)
J3-Pin16(MOSI)——-J3-Pin14(MOSI)
J3-Pin18(CS)———–J3-Pin18(CS)
J3-Pin2(DGND)——–J3-Pin2(DGND)

BBB AM335x:
EVM1(master) ===== EVM2(slave)
P9-Pin31(CLK)——-P9-Pin31(CLK)
P9-Pin29(MISO)——P9-Pin30(MISO)
P9-Pin30(MOSI)——P9-Pin29(MOSI)
P9-Pin28(CS)———P9-Pin28(CS)
P9-Pin1(DGND)——-P9-Pin1(DGND)

K2G EVM:
EVM1(master) ======= EVM2(slave)
J12-Pin9(MISO)——-J12-Pin9(MISO)
J12-Pin11(MOSI)—-J12-Pin11(MOSI)
J12-Pin13(CLK)——J12-Pin13(CLK)
J12-Pin15(CS0)——J12-Pin15(CS0)
J12-Pin49(DGND)–J12-Pin49(DGND)

icev2AMIC110 EVM:
EVM1(master) ======= EVM2(slave)
J5-Pin12(MISO)——-J5-Pin14(MISO)
J5-Pin14(MOSI)——J5-Pin12(MOSI)
J4-Pin13(CLK)——J4-Pin13(CLK)
J5-Pin4(CS)———J5-Pin4(CS)
J5-Pin2(DGND)——-J5-Pin2(DGND)
**On slave EVM console: **SPI initialized
Slave: PASS: Txd from master SPI

**On Master EVM console:
initialized
Master: PASS: Txd from slave SPI
Done
Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)packagesti drvspidocsdoxygenhtmlindex. html
Release Notes $(TI_PDK_INSTALL_DIR)packagesti drvspidocsReleaseNotes_SPI_LL D.pdf

6.8. EDMA3

6.8.1. Overview

6.8.1.1. Introduction

EDMA3 Low Level Driver is targeted to device drivers and applications for submitting and synchronizing EDMA3-based DMA transfers.

EDMA3 is a peripheral that supports data transfers between two memory mapped devices. It supports EDMA as well as QDMA channels for data transfer.

The EDMA3 LLD consists of an EDMA3 Driver and EDMA3 Resource Manager. The EDMA3 Driver provides functionality that allows device drivers and applications for submitting and synchronizing with EDMA3 based DMA transfers. In order to simplify the usage, this component internally uses the services of the EDMA3 Resource Manager and provides one consistent interface for applications or device drivers.

6.8.2. User Interface

6.8.2.1. Driver Configuration

EDMA3 peripheral IP is re-used in different SoCs with only a few configuration changes:

  • Number of DMA and QDMA channels supported
  • Number of PARAM sets available
  • Number of event queues and transfer controllers etc.

The EDMA3 peripheral is used by other peripherals for their DMA needs thus the EDMA3 Driver needs to cater to the requirements of device drivers of these peripherals as well as other application software that may need to use DMA services. Resources for EDMA driver is managed through RM sub module within driver.

6.8.2.2. APIs

API reference for EDMA3 driver

#include <ti/sdo/edma3/drv/edma3_drv.h>

API reference for EDMA3 Resource Management layer

#include <ti/sdo/edma3/rm/edma3_rm.h>

6.8.3. Additional References

EDMA3 Driver Summary
Component Type Library
Install Package EDMA3 Low level drivers
Install Directory <root_install_dir>/edma3_lld_xx_xx_xx_xx
Project Type N/A
Endian Support Little and Big
Library Name edma3_lld_drv.ae66 (little endian), edma3_lld_drv.ae66e (big endian), edma3_lld_drv.aa15fg (A15), edma3_lld_drv.aem4 (M4)
Linker Path <ti/sdo/edma3/drv/lib/[cpu]> <ti/sdo/edma3/rm/lib/[soc-evm]>
Include Paths <ti/sdo/edma3/drv> <ti/sdo/edma3/rm>
Reference Guides See docs under install directory
Additional Resources Programming the EDMA3 using the Low-Level Driver (LLD)
License BSD

EDMA3 sample libs

EDMA3 Driver Sample Summary
Component Type Library
Install Package EDMA3 Low level drivers
Install Directory <root_install_dir>/edma3_lld_xx_xx_xx_xx
Project Type N/A
Endian Support Little and Big
Library Name

edma3_lld_drv_sample.ae66 (little endian), edma3_lld_drv_sample.ae66e (big endian), edma3_lld_drv_sample.aa15fg (A15), edma3_lld_drv_sample.aem4 (M4)

edma3_lld_rm_sample.ae66 (little endian), edma3_lld_rm_sample.ae66e (big endian), edma3_lld_rm_sample.aa15fg (A15), edma3_lld_rm_sample.aem4 (M4)

Linker Path <ti/sdo/edma3/drv/sample/lib/[soc-evm]/[cpu]> <ti/sdo/edma3/rm/sample/lib/[soc-evm]/[cpu]>
Include Paths <ti/sdo/edma3/drv> <ti/sdo/edma3/rm>
Reference Guides See docs under install directory
Additional Resources Programming the EDMA3 using the Low-Level Driver (LLD)
License BSD

6.9. ICSS-EMAC

6.9.1. ICSS-EMAC Driver

6.9.1.1. Introduction

The ICSS_EMAC (industrial communications subsystem Ethernet Media Access Controller) driver provide APIs to transmit and receive packets with a firmware based Ethernet switch that has been implemented on TI’s PRU-ICSS (Programmable Real-Time Unit Subsystem and Industrial Communication SubSystem) 32-bit RISC cores.


Software Architecture

The ICSS EMAC low level driver can be partitioned into the following:

  • Driver software running on the host processor, provides a well defined set of APIs to configure the driver, send packets to the firmware and receive packet from the firmware.
  • Firmware which implements a 2 port ethernet switch supporting 802.1d @100 Mbps. This runs on the TI-PRU-ICSS cores.

Driver Features

ICSS_EMAC LLD implements following:

  • Rx - Copying packet received from firmware and providing it to TCP/IP stack
  • Tx - Providing packet from TCP/IP stack to firmware
  • Learning/Forwarding Data Base
  • Storm Prevention implementation
  • Host Statistics implementation
  • TCP/IP stack related initialization
  • Configuring IP address
  • ARM interrupt management
For details of the driver, please refer to
[1]

6.9.1.2. User Interface

6.9.1.2.1. Driver Configuration
Board Specific Configuration
All the board specific configurations eg: enabling clock and pin-mux for GPIO/MDIP/IEP pins should be performed before calling any driver APIs. By default Board_Init() API supports all initialization sequence for TI supported EVMs. In addition it initializes UART instance for Console/STDIO.Refer Processor SDK RTOS Board Support for additional details.Once board specific configuration is complete driver APIS can be invoked.

ICSS_EMAC Configuration Structure
The icss_emacSoc.c file contains the declaration of the hardware attributes corresponding to the ICSS_EMAC subsystem. Hardware attributes includes base address of various sub-subsystems required by the the ICSS_EMAC LLD. This configuration is required and needs to be passed in as part of the ICSS_EMAC Handle when calling the icss_emacInit API. For details about individual fields of this structure, see the Doxygen help by opening PDK_INSTALL_DIR\packages\ti\drv\icss_emac\docs\doxygen\html\index.html.

6.9.1.2.2. APIs

API reference for application:

#include <ti/drv/icss_emac/icss_emacDrv.h>

API Call Flow

The below sequence indicates the calling sequence of ICSS_EMAC driver APIs for a use case of an EMAC example which implements single Ethernet MAC using PRU-ICSS Instance 2, ETH0. For additional details refer example inside package

...
Board_init(cfg);

/* Perform MDIO init */
ICSS_EMAC_testMdioInit(CSL_MPU_PRUSS2_U_MII_MDIO_REGS);
/* Create handle for PRUICSS instance*/
ICSS_EMAC_testPruIcssHandle2= PRUICSS_create(pruss_config,2);

/* Setup crossbar configuration to receive PRU-ICSS interrupts and map them to A15 (illustration for PRU2ETH0) */
CSL_xbarDspIrqConfigure(..);  /* Link ISR */
CSL_xbarDspIrqConfigure(..);  /* RX PKT ISR */
CSL_xbarDspIrqConfigure(..);  /* TX PKT ISR */
/*Initialize driver */
...
ICSS_EmacInit(..);

/* Register callbacks for RX/TX, Link Interrupts, these are called in context of ISR */
ICSS_EmacRegisterPort0ISRCallback(..);
ICSS_EmacRegisterHwIntRx(..);
ICSS_EmacRegisterHwIntTx(..);
/* Enable interrupts for RX/TX/Link*/
ICSS_EMAC_testInterruptInit(ICSS_EMAC_testHandle2);
/* Enable Link Interrupt in MDIO sub-system */
ICSS_EMAC_testMdioEnableLinkInterrupt(..);
/* At this point, ICSS_EMAC LLD APIs can be called */
</syntaxhighlight>

Firmware

TI PRU-ICSS cores (Programmable Real-Time Unit Industrial Communication Subsystem) is firmware programmable and can take on various personalities. Examples include an SORTE, ethernet Switch, Industrial protocol switch. Please refer to ICSS-EMAC Firmwares for further explanation.


6.9.1.3. Application

6.9.1.3.1. Examples

Refer “ICSS_EMAC_<Basic/Switch>Example_<SOC>_<CPU>Testproject” for additional reference. Refer Release Note for ICSS_EMAC supported on different EVMs.

Name
Description
EVM Configuration
Expected Results
ICSS_EMAC_Basic Example

EMAC Loopback test at PRU-ICSS EMAC PHY.

Example demonstrates loopback capability by sending dummy broadcast packet to PRU-ICSS instance 2, ethernet port 0 (PRU ETH0). Unit test registers receive packet callback routine with LLD to be called for RX packet. Call back routine will extract packet received, perform simple memory comparison against packet sent for integrity check. Unit test will iterate 10 times for packet transmission and reception check.
10/100 Mb/s loopback cable Unit Test will print “All tests have passed” via UART console.
ICSS_EMAC_Switc hExample

Switch Loopback test at PRU-ICSS EMAC PHY.

Example demonstrates switch learning loopback capability by sending dummy broadcast packet to PRU-ICSS instance, ethernet port. Unit test registers receive packet callback routine with LLD to be called for RX packet. Call back routine will extract packet received, perform simple memory comparison against packet sent for integrity check. As with switch for every 1 transmitted packet, firmware will respond back with 2 recieved packets. Unit test will iterate 10 times for packet transmission and reception check.
100 Mb/s loopback cable Unit Test will print “All tests have passed” via UART console.

6.9.1.4. Debug Guide

For debugging ICSS EMAC examples or LLD. Please refer to ICSS-EMAC Debug Guide.

6.9.1.5. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\icss_emac\docs\doxygen\html\ index.html
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \drv\icss_emac\docs\ReleaseNotes_ ICSS_EMAC_LLD.pdf
ICSS-EMAC LLD Details [2]

6.9.2. Development with ICSS-EMAC Driver

6.9.2.1. Terms and Glossary

Table 6.1 Glossary
Abbreviation Meaning Abbreviation Meaning
ICSS Industrial Communicatin Sub-System SDK Industrial Software Development Kit
PRU Programmable Real Time Unit INTC Interrupt Controller
LLD Low Level Driver SoC System On Chip. Platforms like AM335x/AM437x etc
EMAC Ethernet MAC RTOS Real Time Operating System
TRM Technical Reference Manual for an SoC. Such as this. DLR Device Level Ring - a redundancy protocol for EtherNet/IP.
Rx/Tx Packet Receive/Packet Transmit Host/CPU/Cortex Used interchangeably and refers to the Application Processor

  • Bold typeface refers to name of function/API/variable/structure.
  • Code snippets are shown as below
Sample code snippet

6.9.2.2. Document Revision Table

Table 6.2 Document Revision
Date Revision Comments
02-Oct-2015 v.1.0 Initial Release
04-Oct-2015 v.1.1 Fixed links and images
04-July-2016 v.1.2 Added Time Triggered Send details

6.9.2.3. Introduction

The Industrial SDK release from Texas Instruments enables the use of the PRU-ICSS for ethernet packet processing. This is used to implement several Industrial Ethernet based protocols including Profinet, EtherNet/IP, EtherCAT etc., The SDK contains one example for each protocol. These are available under SDK/public/examples. For more information on protocols, examples, folder structure and information on how to use the SDK, please refer to the Getting Started Guide.

In addition to these, the SDK comes with an Ethernet MAC example. This example uses two PRU’s to implement two independent MAC’s with two different MAC addresses and two different IP addresses. To provide an analogy, this is somewhat similar to a two port Ethernet PCIe NIC card on a PC, only here, the Ethernet interface is available along with the Host processor on a single SoC.

Since all the Industrial protocols and Ethernet MAC share the same basic software architecture a discussion of Ethernet MAC goes a long way in understanding the implementation of other protocols. This is a recommended reading for anyone trying to develop or use other Ethernet based protocols provided in the SDK.

6.9.2.3.1. Assumption

The guide is geared towards helping developers with starting to build applications using the Ethernet MAC and as such does not contain extensive architectural and design information. Readers are expected to be well versed with PRU-ICSS hardware architecture and peripherals. A description of the PRU-ICSS can be found here.

This guide also assumes general familiarity with the SDK structure and Industrial EVM’s. If you are not familiar with this then please go through the Getting Started Guide mentioned previously.

Current SDK release 2.1.0.1 covers both AM335x and AM437x platforms, please refer to the TRM’s for details on the SoC. The TRM’s can be found here. AM335x/AM437x.

6.9.2.3.2. Scope of the Document

This document:

  • Enables a developer to build simple applications using the Ethernet Driver and the sample Ethernet MAC application
  • Explains the components, software organization and architecture of the Ethernet driver briefly. This is only to enable developers to use and debug the modules. A detailed discussion of the architecture is beyond the scope of this document.
  • Explains usage and simple tasks through use cases and examples
  • Helps port another TCP/IP Stack or RTOS for the Ethernet MAC example

The document follows a hands on approach and different aspects are explained through examples and code snippets, these in turn are derived from questions on the forum and field.

To prevent the guide from becoming too big and to limit it’s scope a separate debugging guide has been written which covers various other aspects such as Q&A’s and Debug examples with screenshots. The two documents must be used in conjunction to utilize them fully.

Note

The code snippets in this guide are only informative, they may or may not compile if taken as it is. Developers are requested to consult the API guide and other relevant user guides for exact coding details.

6.9.2.4. Software Architecture

The ICSS EMAC consists of driver + firmware implementation. Firmware refers to the code running on the two PRU’s which are part of ICSS while driver refers to that portion of code running on host which is directly associated with the firmware. The two PRU’s are responsible for reception of packets while Host runs higher level tasks.

Logically the software on host can be partitioned into

  • Ethernet Driver - Copying packet data and providing to upper layers. Managing PRU/ICSS.
  • TCP/IP and other network stack. NDK in this case.
  • RTOS code. SYS/BIOS in this case.
  • Peripheral initialization and management.

Out of these the first three are relevant to this discussion. Only the driver is discussed in depth while NDK and SYS/BIOS are mentioned in passing whenever relevant.

6.9.2.4.1. File Organization

SDK Folder structure is covered in the SDK User Guide here. This guide only covers the contents of the folder referred to as os_drivers in the user guide.

The contents of the folder os_drivers are discussed briefly:

  • *lld* - Refers to Link Layer Driver. This contains the core of the driver which implements the following:
    • Rx - Copying the packet received from the firmware and providing it to the TCP/IP stack
    • Tx - Providing packet from TCP/IP stack to the firmware
    • Learning/Forwarding Data Base - refer here
    • Storm Prevention implementation - refer here
    • Host Statistics implementation - refer here
  • *pruss* - Refers to the software which manages the PRU. It performs the following tasks
    • Initializing the PRU memory
    • Populating memory offsets, MAC addresses in PRU memory
    • Managing PRU Interrupt Controller
  • *ICSS* - Contains software related to the NDK (TCP/IP) Interface.
    • TCP/IP stack related initialization
    • Configuring IP address
    • ARM interrupt management
6.9.2.4.2. EMAC and Switch

It is important to differentiate between the two different types of implementations in SDK context because this keeps coming up while discussing SDK and it’s components. An EMAC example implements two independent Ethernet MAC’s using PRU 0/1, they have two different MAC, IP addresses and two different instances of the TCP/IP stack while a Switch presents a single IP and MAC address for any external entity. Another important difference which is obvious from the name is that an EMAC does not forward a packet from one port to another like a Switch.

SDK only provides a separate EMAC example, right now there is no example in the SDK for a standalone Switch on the lines of EMAC. The example that comes close to it is the EtherNetIP adapter which is a standalone Ethernet Switch running a EtherNet/IP protocol stack. Instructions on how to remove the EtherNet/IP part of it are given here.

There are some important differences between an EMAC and Switch


Table 6.3 Differences between EMAC and Switch
EMAC Ethernet Switch (Profinet and EtherNet/IP)
Two interface MAC addresses Single interface MAC address
PRU0 transmits on Port0 and PRU1 on Port1 PRU0 transmits on Port1 and PRU1 on Port0
Two TCP/IP instances and two IP addresses One TCP/IP instance and one IP address
Two Rx interrupts, semaphores and tasks for two ports Single Rx interrupt, semaphore and task
Two ICSS EMAC Handles Single ICSS EMAC Handle
No collision handling (independent MAC’s) Collision buffer with Collision Handling Collision refers to Queue Contention
No forwarding of packets Packets forwarded depending on forwarding rules
6.9.2.4.3. Ports in Driver context

Before beginning it’s important to explain the conventions used in this document, although there are two physical ports for every ICSS for the sake of convenience the Host is considered as a third port. In fact for some protocols this is the logical partitioning used. The convention used here is two physical ports and one host port.

The ports are referred to as

  • Host Port - ICSS_EMAC_PORT_0
  • Physical Port 0 - ICSS_EMAC_PORT_1
  • Physical Port 1 - ICSS_EMAC_PORT_2

This convention is followed throughout the document as well as inside the driver and firmware.

6.9.2.4.4. Driver Architecture and Memory Map

A detailed discussion of the architecture is beyond the scope of this document. A brief summary is provided below to explain where the data is copied to, how and why.

While discussing the ICSS Switch we are mainly concerned with 4 types of memories.

6.9.2.4.4.1. DDR

This is the memory from where ARM core operates. It’s not on the SoC and hence has a lower performance. This is cached.

This contains

  • TCP/IP Buffers.
  • Learning/FDB tables.
  • Host Statistics.
  • Control structures and variables.
6.9.2.4.4.2. L3 OCMC RAM

This is where the actual packet buffers or queues are located. There are 15 queues (Switch) or 12 queues (EMAC) in total. 4 queues for each port (including host) and 1 additional queue for each port to handle collision. This is covered later in QoS section. Developer needs to know that firmware copies the packet data here after receiving them and this is where the driver writes the packet data meant for transmission using the firmware. So this acts as a place holder for packet data before it received or transmitted. This memory resides inside the SoC (but outside ICSS) and is faster than DDR. It’s buffered but non-cached. Size varies from SoC to SoC, please refer to the TRM for more details. The L3 OCMC RAM contains:

  • Host receive queues
  • Port transmit queues
  • Collision queues (not in EMAC mode)

Note

This memory map is applicable only for EMAC application. Other applications might have their own map.

6.9.2.4.4.3. Shared Data RAM

This is specific to the PRU subsystem although access is possible from Host albeit slowly. Data common to both PRU’s such as Host queue descriptors are stored here. A lot of the memory is available for protocol or application specific usage, for more details refer to the memory map. Size varies from SoC to SoC, please refer to the TRM for more details. The Shared Data RAM contains

  • Host queue descriptors
  • Buffer descriptors for all 12 queues
  • Host Rx Context for 4 Host receive queues

Note

This memory map is applicable only for EMAC application. Other applications might have their own map.

6.9.2.4.4.4. PRU0 Data RAM

This is similar to Shared Data RAM though meant for use only by PRU0. Access from PRU1 is also possible, so the separation is only logical, not in hardware. Size varies from SoC to SoC, please refer to the TRM for more details. The PRU0 Data RAM contains:

  • Port 0 Time Triggered Send variables
  • Port 0 Queue descriptors for 4 Tx queues
  • Port 0 Tx Context for 4 Port Tx queues
  • Port 0 Statistics
  • Port 0 MAC ID
  • Port 0 Port, Speed and Duplex information

Note

This memory map is applicable only for EMAC application. Other applications might have their own map.

6.9.2.4.4.5. PRU1 Data RAM

Similar to PRU0 Data RAM but for PRU1.

6.9.2.4.5. Quality of Service and Queues

Quality of Service is very important for an Ethernet Switch/EMAC as it allows high priority packets to be processed separately from regular packets. This provides reliability for real time traffic. In EMAC this is done using queues which are mapped to 8 VLAN based priority levels. Each queue is a block of memory on L3 used to store the packet data. Queue sizes may vary and are build time configurable from icss_emacSwitch.h, for example host queue sizes used for default EMAC application are given below, the sizes are denoted by blocks. Each block is 32 bytes in size. The sizes are limited by L3 size which are dictated by SoC. For in depth information on how to re-build the icss-emac LLD PDK component in case your use case requires re-sizing the Queue sizes, refer to [1].

#define HOST_QUEUE_1_SIZE      194
#define HOST_QUEUE_2_SIZE       194
#define HOST_QUEUE_3_SIZE       194
#define HOST_QUEUE_4_SIZE       194

The transmit queues sizes are denoted separately

#define QUEUE_1_SIZE       97
#define QUEUE_2_SIZE        97
#define QUEUE_3_SIZE        97
#define QUEUE_4_SIZE        97

So in total there are 15 queues (12 queues in EMAC), 4 receive queues for Host and 4 transmit queues for each of the two physical ports. In addition to these there is 1 collision queue each for Host and 2 ports which can hold one packet irrespective of packet size.

Note

There are no collision queues in EMAC.

The figure below is illustrative to remember this

6.9.2.4.5.1. How QoS Works
6.9.2.4.5.1.1. Switch QoS

When a packet is received in firmware, the 3 bit PCP field of the VLAN tag is read and the packet is copied to the appropriate queue based on fixed mapping which maps 2 levels(out of 8) of QoS to one queue. So 7 & 6 map to Queue 4, 5 & 4 to Queue 3 and so on. On the driver this queue number then translates to the priority value and is used to decide how to process the packet. If a packet is missing VLAN tag then the lowest priority queue Queue 4 is chosen.

6.9.2.4.5.1.2. EMAC QoS

PCP to queue mapping is different for EMAC. In EMAC, the 4 Host receive queues are split into two groups. Queue 1 and Queue 2 are used for storing packets received at PRU0/Port1 and Queue 3 and Queue 4 are used for storing packets received at PRU1/Port2. So, the low priority queues are Queue 2 and Queue 4 for Port 1 and Port 2 respectively. Queue 1 and Queue 3 are high priority queues for Port 1 and Port 2 respectively.

  • All the non-VLAN tagged frames are stored in the lowest priority queue (Queue 2 for Port 1 and Queue 4 for Port 2).
  • VLAN tagged frames with “Priority Code Point (PCP)” value of 4, 5, 6 and 7 are stored in highest priority queue (Queue 1 for Port 1 and Queue 3 for Port 2).
  • VLAN tagged frames with “Priority Code Point (PCP)” value of 0, 1, 2, and 3 are stored in low priority queue (Queue 2 for Port 1 and Queue 4 for Port 2).

More on this in the next section where driver side Rx processing is discussed in detail.

Note

  • When a queue overflows, packets are not automatically copied to the next free queue. So overflow can occur.
  • Contention/Collision queue can only handle a single packet irrespective of size, anything above is dropped.
  • On Tx side, there is no special handling with regards to QoS. Data is copied to one of the four queues based on the queuePriority field ICSS_EmacTxArgument structure passed to the ICSS_EmacTxPacket API.
  • At the moment driver/firmware doesn’t support DSCP.
6.9.2.4.6. Data Path

Data path refers to the control flow which is executed on the driver and firmware to send or receive a packet. A basic understanding of it goes a long way in explaining the software architecture and if a developer is only trying to use the Rx and Tx capabilities of EMAC or Switch a knowledge of this is sufficient to build an application.

6.9.2.4.6.1. Rx Data Path

Packets are received in the ICSS from where they are copied by the PRU’s to L3 memory. The PRU’s then assert an interrupt to tell the Host about the presence of a packet. PRU avoids corruption and does not write over the memory till the packet is copied by the Host.

The flowchart shown above shows the sequence in very broad strokes. A detailed description is given below.

  1. PRU Posts an Rx interrupt to the ARM interrupt controller. For EMAC each PRU has a separate Rx interrupt, the configuration for which is done in the application (details in Interrupts).
  2. The interrupt triggers the ISR ICSS_EmacRxInterruptHandler which in turn posts a semaphore rxSemaphoreHandle to signal RxTask to empty the Rx queues.
  3. The RxTask function goes through all the queues, extracts the port/queue number and provides it to an API which copies data from L3 to DDR. The code excerpt is shown below with explanations.
/*Read till all queues are empty*/
while(allQueuesEempty != 1 && numPacketsInLoop <= ((((ICSSEMAC_Object*)icssEmacHandle->object)->emacInitcfg)->pacingThreshold))
{
     /*This API reads the queues and gets the queue and port number for each packet*/
     pLength = ICSS_EmacRxPktInfo(icssEmacHandle, &port_number, &queue_number);
     if(pLength > 0)
     {
          if(queue_number >= ((ICSSEMAC_Object*)(icssEmacHandle->object))->emacInitcfg->ethPrioQueue)
          {
               /*Based on queue priority settings decide if the packet is to be sent to the TCP/IP stack*/
               /*This API is hooked to NDK*/
               icssEmacHwIntRx(&queue_number,icssEmacHandle);
          }
          else
          {
               /*Protocol specific callback*/
               if(((((ICSSEMAC_Object*)icssEmacHandle->object)->callBackHandle)->rxRTCallBack)->callBack != NULL)
               {
                    ((((ICSSEMAC_Object*)icssEmacHandle->object)->callBackHandle)->rxRTCallBack)->callBack(&queue_number,
                    ((((ICSSEMAC_Object*)icssEmacHandle->object)->callBackHandle)->rxRTCallBack)->userArg);
               }
               else
               {
                    /* just dump the packet here so we do no stall the queues*/
                    ICSS_EmacRxPktGet(icssEmacHandle,(uint32_t)dest_address, queue_number, &port_number, &more);
               }
          }
          ...
          ...
}

In the code snippet above, function ICSS_EmacRxPktInfo goes through each queue one at a time, extracts the port & queue number information for every packet and provides it to functions below. Based on the priority of the packet which is decided by the queue number (refer to discussion on QoS and queues) driver decides to either forward it to NDK, done by icssEmacHwIntRx or give it to the callback function.

The threshold for this decision is decided by the user settable parameter shown in the code above.

((ICSSEMAC_Object*)(icssEmacHandle->object))->emacInitcfg->ethPrioQueue)

Anything lower than this configured value goes to the callback function. If a callback is not registered then the queue is just emptied to prevent queues from overflowing. This is done by the function ICSS_EmacRxPktGet which takes a single packet and copies it into dest_address provided as a parameter. This is not a dummy API but a basic Rx API which performs the task of copying data from L3 to DDR, even the NDK API icssEmacHwIntRx internally calls ICSS_EmacRxPktGet to fetch the packet data.

If a developer is building a custom API to process packets then he/she needs to call the API ICSS_EmacRxPktGet in their respective function, this is explained with an example below.

*Doing customized packet processing:*

This example is taken from EtherNet/IP adapter application where some DLR packets are processed different from other packets using a callback. For this example the value of ethPrioQueue is set to 4 or ICSS_EMAC_QUEUEPRIO4 and in this case these DLR frames have a the highest priority so they go to the callback function, developers need to set an appropriate value for ethPrioQueue based on their requirements. The callback is configured in main like this (taken from icss_eip_driver.c)

/*Packet processing callback*/
((((ICSSEMAC_Object*)icssEmacHandle->object)->callBackHandle)->rxRTCallBack)->callBack = (ICSS_EmacCallBack)processProtocolFrames;
((((ICSSEMAC_Object*)icssEmacHandle->object)->callBackHandle)->rxRTCallBack)->userArg = icssEmacHandle;

Where icssEmacHandle is the main driver handle and processProtocolFrames is the callback function whose outline is given below

void processProtocolFrames(uint32_t* queue_number, void* userArg) {
...
...
uint8_t *dstMacId = tempFrame;
ICSSEMAC_Handle eipIcssEmacHandle = (ICSSEMAC_Handle)userArg;
/*Fetch the packet*/
size = ICSS_EmacRxPktGet(eipIcssEmacHandle,(uint32_t)tempFrame, *queue_number, &port, &more);
...
/*Compare Destination MAC ID and determine if this is a DLR packet*/
if(COMPARE_MAC(dstMacId, dlrMAC)) {
  processDLRFrame(eipIcssEmacHandle, tempFrame, port-1, size);
...
...
}

As can be seen processProtocolFrames function calls ICSS_EmacRxPktGet internally and passes the data to processDLRFrame for further processing.

6.9.2.4.6.2. Tx Data Path

The Transmit path on host is simpler than the Rx path. As far as the developer is concerned the main API call is ICSS_EmacTxPacket. This API implements the Learning/FDB functionality. ICSS_EmacTxPacket in turn calls another API ICSS_EmacTxPacketEnqueue which performs the actual task of copying data from DDR to L3 and signals the PRU to transmit the data. ICSS_EmacTxPacket when called with the parameter ICSS_EMAC_PORT_0 in portNumber field enables learning/FDB and calls the ICSS_EmacTxPacketEnqueue with the correct port number and when called with parameter ICSS_EMAC_PORT_1 or ICSS_EMAC_PORT_1 the API directly calls the underlying API. To avoid confusion developers must always call the API ICSS_EmacTxPacket (NOT [STRIKEOUT:ICSS_EmacTxPacketEnqueue]) with portNumber as

  • ICSS_EMAC_PORT_0 : If they do not know the port number on which to transmit.
  • ICSS_EMAC_PORT_1 or ICSS_EMAC_PORT_2 : If they know the port number

Note

Firmware automatically appends CRC to the packet on Transmit path.

6.9.2.4.6.3. Usage

For simple and/or non time critical applications, it makes more sense to use the NDK socket API’s to perform Receive and Transmit operations. An example using NDK sockets which performs both Rx and Tx is given below. For in depth information on how to use sockets please consult NDK User’s guide and NDK API Reference guide.

/*Transmit to System with IP Address*/
#define DST_IP "192.168.1.64"
#define DST_PORT 7
/*Open file session*/
fdOpenSession( (HANDLE)Task_self() );
SOCKET s = INVALID_SOCKET;
struct sockaddr_in sin1;
struct timeval timeout;
/*Create UDP socket*/
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
/*Prepare address for connect*/
IPN IPAddr;
IPAddr = inet_addr(DST_IP);
bzero( &sin1, sizeof(struct sockaddr_in) );
sin1.sin_family = AF_INET;
sin1.sin_addr.s_addr = IPAddr;
sin1.sin_port = htons(DST_PORT);
 /*Configure our Tx and Rx timeout*/
timeout.tv_sec = 0;
timeout.tv_usec = 1;
setsockopt( s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof( timeout ) );
setsockopt( s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof( timeout ) );
/*Transmit packet*/
sendto( s, pBuf, testsize, 0, (PSA)&sin1, sizeof(sin1) );
/*Receive packet*/
recv(s, pBuf, MAX_UDP_SIZE, 0);

For time critical applications with low latency requirements directly calling the API’s is recommended. For Transmit this can be done by populating the packet directly(or through a stack) in a memory buffer and calling ICSS_EmacTxPacket with the buffer in a task in main(). Shown below is an example of a periodic transmit being done in main function.

/**A dummy packet*/
uint8_t dummyPkt[ETHERNET_FRAME_SIZE_60] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,
0x45,0x00,0x00,0x2E,0x00,0x00,0x40,0x00,0x40,0x00,0x3A,0xD1};
Void taskSendPacket(UArg a0, UArg a1) {
  /*wait for system to initialize*/
  /*Send packet in a loop every 500ms*/
  Task_sleep(5000);
  while(1) {
    /*Send packet on PORT 1*. Size is known previously/
    ICSS_EmacTxPacket(emachandle,dummyPkt, ICSS_EMAC_PORT_1, 1, ETHERNET_FRAME_SIZE_60);
    Task_sleep(500);
  }
}

For receive the application/stack can receive the packet data directly in (uint32_t)dest_address from ICSS_EmacRxPktGet inside RxTask. Modify the ethPrioQueue value as per requirement. (Explained above)

6.9.2.4.6.4. Forwarding Rules

Forwarding Rules specify how packets are forwarded between ports and from the port to the Host. There are three basic types of forwarding scenarios. The image below shows all modes when receiving on first port. HW Port represents the physical port. These modes are not exclusive to each other and multiple modes are also allowed.

Please note that EMAC can only forward to the Host, other modes only apply to switch.

  • Cut Through - In this mode the firmware copies the data from Rx FIFO to Tx FIFO through the registers. No data is copied to the queues, this is the fastest mode of transmit from one port to another. Advantage is low latency, disadvantage is that CRC is not checked before transmit since it lies at the end of the packet.
  • Store & Forward - In this mode the firmware copies the received data to the transmit queues on opposite port, no data is sent to the Host (Rx interrupt on Host is not asserted). CRC is checked before transmit. Many protocols like PTP use this mode.
  • Forward to Host - Data is received in the Host receive queues and an Rx interrupt is asserted to copy the data. This is the only mode available for an EMAC.

Table 6.4 Forwarding Rules
Packet Type Forwarding Mode
Broadcast Cut through & Forward to Host
Multicast Cut through & Forward to Host Multicast frames like PTP/DLR are handled based on protocol
Unicast (not to Host) Cut through
Unicast (to Host) Forward to Host

6.9.2.4.7. Interrupts and Tasks

This section deals with Interrupts and Tasks required to implement an EMAC LLD application. Since they are tied to the RTOS used, they are exported via the driver handle to the application as well as through the OSAL layer. Developers must take care to maintain correct priorities and order so as not to alter the behavior of the driver. All the interrupts and tasks enabled in an application can be checked using the SYSBIOS ROV. For more details on this tool refer to the SYSBIOS section of EMAC LLD Debug Guide.

6.9.2.4.7.1. Interrupts

There are six interrupts (eight if time triggered send is enabled) in an EMAC LLD coming from PRU. Other implementations like EtherNet/IP, PTP, Profinet etc may use their own interrupts. Please note that there are individual interrupts for each port because this is a dual MAC implementation, for an Ethernet switch like EtherNet/IP there are only two interrupts (no time triggered send in Switch mode).

The eight interrupts are:

  1. Rx interrupt x 2 : One for each port, both mapping to same ISR. These are used by PRU to tell ARM about the presence of a packet. For Port 0 this is interrupt number (ARM) 20 on AM335x and for Port 1 it is 21. In the mapping these are indicated by PRU_ARM_EVENT0 and PRU_ARM_EVENT1 respectively. For ethernet switch it’s just PRU_ARM_EVENT0.
  2. Link interrupt x 2: One for each port, both mapping to same ISR. These are used to indicate PHY state change to Host. For Port 0 interrupt number (ARM) is 26 and for Port 1 27. In mapping these are indicated by MII_LINK0_EVENT and MII_LINK1_EVENT which map to CHANNEL7 and CHANNEL8 respectively. For ethernet switch both link events map to a single channel CHANNEL7.
  3. Tx Completion Interrupt x 2: One for each port, mapping to different ISRs. These are used by PRU to tell ARM about the completion of transmission of a packet. For Port 0 this is interrupt number (ARM) 22 on AM335x and for Port 1 it is 23. In the mapping these are indicated by PRU_ARM_EVENT2 and PRU_ARM_EVENT3 respectively.
  4. TTS Insert Cyclic Frame Interrupt x 2: One for each port, mapping to different ISRs. These are used by PRU to tell ARM that its time to insert cyclic frame. For Port 0 this is interrupt number (ARM) 22 on AM335x and for Port 1 it is 23. In the mapping these are indicated by PRU_ARM_EVENT4 and PRU_ARM_EVENT5 respectively. These are only applicable when TTS is enabled and initialized by the application.

Note

Tx Completion Interrupts and TTS Cyclic Frame Interrupts are different PRU events, i.e., total 4 PRU events. But these map to the same interrupt and ISR per port i.e., Tx Completion Interrupt and TTS Cyclic Frame Interrupt share one ARM interrupt number and ISR for Port 1 and share one ARM interrupt number and ISR for Port 2.

There are two types of interrupts:

  • *ICSS Interrupts* : These are interrupts that are routed through the ICSS Interrupt controller to the Host (Refer to section 4.4.2 of AM335x TRM). It consists of interrupts asserted by the PRU as well as interrupts asserted by the peripherals (MDIO, ECAP etc) attached to the ICSS Interrupt controller.

The Host Interrupt controller has 8 usable interrupts mapped to the ICSS interrupt controller. This mapping is programmable and varies from example to example. Every example has a x_pruss_intc_mapping.h file in the sdk/examples folder where x stands for the example name. For EMAC this file is called tiemac_pruss_intc_mapping.h.

*Mapping Explanation*

The interrupt mapping consists of 3 parts:

  1. 8 PRU user interrupts (can be set in the firmware by writing to R31) - represented by PRU_ARM_EVENT0 to PRU_ARM_EVENT7. These are part of the 64 system interrupts (out of which 32 are usable). This includes the two link interrupts for two ports MII_LINK0_EVENT and MII_LINK1_EVENT.
  2. 10 ICSS Host channels CHANNEL0 to CHANNEL9 out of which the first two CHANNEL0 and CHANNEL1 are used internally.
  3. 8 ARM PRU interrupts represented by PRU_EVTOUT0 to PRU_EVTOUT7. These can also be seen in the ARM INTC in SoC TRM. Provided below is a screenshot from AM335x TRM showing the 8 interrupts mapped to the PRU.


The complete mapping follows the pattern
PRU user interrupts --> Host Channels --> ARM PRU Interrupts

To take an example of Rx interrupt for Port 0 (EMAC only). For switch this is the Rx interrupt for both ports.

The following line maps PRU user interrupt 0 to Host channel 2.

{PRU_ARM_EVENT0,CHANNEL2, SYS_EVT_POLARITY_HIGH ,SYS_EVT_TYPE_PULSE}

Host channel CHANNEL2 in turn maps to the first ARM interrupt PRU_ICSS_EVTOUT_0 through this line.

{CHANNEL2, PRU_EVTOUT0}

As seen from the screenshot the interrupt number for PRU_ICSS_EVTOUT_0 on AM335x is 20, so the interrupt number that must be configured for this in application should be 20 if the platform is AM335x. This is done in the following line (defined in main.c)

switchEmacCfg->rxIntNum = 20;

This mapping alone determines which ARM interrupt number will be associated with a particular PRU user interrupt. For example the line above where PRU user interrupt 0 maps to Host channel 2 can be modified to

{PRU_ARM_EVENT0,CHANNEL2, SYS_EVT_POLARITY_HIGH ,SYS_EVT_TYPE_PULSE} ---> {PRU_ARM_EVENT0,CHANNEL4, SYS_EVT_POLARITY_HIGH ,SYS_EVT_TYPE_PULSE}

and the Channel to ARM interrupt map can be configured as, and the interrupt number on ARM would still remain the same i.e. 20

{CHANNEL2, PRU_EVTOUT0} --->  {CHANNEL4, PRU_EVTOUT0}

A question arises in this case as to the usefulness of CHANNELx. The answer is that channels allow us to map multiple PRU User interrupts and system interrupts to a single channel and in turn to a single ARM interrupt. For example take a look at the link interrupt mapping

{MII_LINK0_EVENT, CHANNEL7, SYS_EVT_POLARITY_HIGH ,SYS_EVT_TYPE_PULSE},    \
{MII_LINK1_EVENT, CHANNEL7, SYS_EVT_POLARITY_HIGH ,SYS_EVT_TYPE_PULSE}, \

and

{CHANNEL7, PRU_EVTOUT6}

This configuration maps both Port 0 and Port 1 interrupts to a single channel and in turn to a single ARM interrupt PRU_ICSS_EVTOUT6, which is interrupt number 26 (shown by the line below in main.c)

switchEmacCfg->linkIntNum=26;

The link interrupt binds to a single ISR ICSS_EmacLinkISR on Host. Inside the ISR an ICSS register HW_ICSS_INTC_SECR1is checked to find out which link event MII_LINK0_EVENT or MII_LINK1_EVENT asserted the interrupt. The advantage of such an approach is that both interrupts are serviced even if they are raised at the same time.

These interrupt numbers can change from SoC to SoC so please consult TRM before making any modifications to the interrupt map. This is also one of the reasons for exporting these configurations to application so that a single driver can handle multiple SoC’s others being ease of use, porting other operating systems etc.


Table 6.5 PRU Interrupt Mapping in EMAC
PRU Interrupt Number Channel Number Host Interrupt Number ISR
PRU_ARM_EVENT0 Port 0 RX Interrupt CHANNEL2 20 ICSS_EmacRxInt erruptHandler
PRU_ARM_EVENT1 Port 1 RX Interrupt CHANNEL3 21 ICSS_EmacRxInt erruptHandler
PRU_ARM_EVENT2 Port 0 TX Completion Interrupt CHANNEL4 22 ICSS_EmacTxInt erruptHandlerPo rt1
PRU_ARM_EVENT3 Port 1 TX Completion Interrupt CHANNEL5 23 ICSS_EmacTxInt erruptHandlerPo rt2
PRU_ARM_EVENT4 Port 0 TTS Insert Cyclic Frame Interrupt CHANNEL4 22 ICSS_EmacTxInt erruptHandlerPo rt1
PRU_ARM_EVENT5 Port 1 TTS Insert Cyclic Frame Interrupt CHANNEL5 23 ICSS_EmacTxInt erruptHandlerPo rt2
MII_LINK0_EVENT Port 0 Link Interrupt CHANNEL7 26 ICSS_EmacLinkI SR
MII_LINK1_EVENT Port 1 Link Interrupt CHANNEL8 27 ICSS_EmacLinkI SR

  • *Host Interrupts* : Host interrupts are interrupts that are not coming via ICSS Interrupt controller. These include peripherals, EDMA, timers etc. A full list is present inside the Interrupt section of any TRM. On AM335x a total of 128 interrupts are available through this (including 8 PRU ICSS interrupts). Discussion of Host interrupts is beyond the scope of this guide as we only deal with the EMAC LLD driver here.

Some examples of Host interrupts used in the driver are DMTimer interrupts and EDMA interrupts which are available through the OSAL layer osdrv_edma.c and osdrv_osal.c

6.9.2.4.7.2. Interrupt Pacing

When packets are sent to the Host at a very high rate (this happens more often with small frames) it’s possible that ARM is interrupted frequently by the PRU’s, this results in packets getting dropped as the host is unable to empty the queues in time because of context switching. Interrupt pacing is a scheme used to cope with this situation. In this scheme interrupts are disabled when the first Rx interrupt is received (The PRU still keeps receiving the frames and putting them on the queues), after a certain number of packets have been processed on the Host, the interrupts are enabled once more. Since interrupts on PRU have not been disabled any pending packets will assert the interrupt again, this ensures that no packets are missed. The advantage of pacing is that a greater throughput is achieved while disadvantage is that if any critical packets need to be serviced immediately, it’s possible that some delay may occur. Pacing is enabled in the driver using the variable intrPacingMode. There are two pacing modes in driver.

  • INTR_PACING_MODE1 : This is entirely ARM based, i.e. interrupts are disabled only on the Host. This does not require any firmware support. This is the scheme supported with Ethernet MAC and Ethernet IP Adapter.
  • INTR_PACING_MODE1 : In this scheme interrupts are disabled on the PRU. This requires firmware support. Only supported in Profinet right now.
6.9.2.4.7.3. Tasks

Tasks are the Linux equivalent of processes in SysBIOS. A simple example to create a task from EMAC application is given below

Task_Params_init(&taskParams);
taskParams.priority = 15;
taskParams.instance->name = "SwitchTask";
Task_create(taskPruss, &taskParams, &eb);

Here taskPruss is given the job of initializing the PRU’s and loading the firmware onto them. The task itself is a simple function with two arguments

/*
 *  ---task to initialize PRU---
 */
Void taskPruss(UArg a0, UArg a1)
{
  ...
  ...
  ...
}

They can be used for simple tasks like sending or receiving a packet. To get an idea refer to the example usage for sending a packet through a call to transmit API ICSS_EmacTxPacket in a loop. If calling the task in an endless while loop developers must add a small delay inside the loop using Task_sleep(time in milliseconds) to let other tasks get some time as well, failure to do so is a common mistake that developers make.

6.9.2.4.8. Learning/FDB

Learning/FDB where FDB stands for Forwarding Data Base is a module that learns source MAC addresses of packets addressed to the Host and thus maintains a list of which devices reside on which port. While transmitting a packet when provided with the destination MAC address the module returns the port number on which the device resides. This avoids duplication of traffic on both ports. This module is applicable only in Switch mode, in EMAC mode this module is disabled since there is only one port.

6.9.2.4.8.1. Design

Learning table is currently implemented as a Hash table. There is one table for each physical port. Each table has 256 buckets where a bucket has a size of 4. The bucket size and number of buckets are in turn dictated by the choice of Hashing algorithm. A detailed discussion on this topic is beyond the scope of this document, suffice to say that theoretically a hash table is capable of learning 256 * 4 = 1024 entries. The actual capacity may be lower owing to collisions.

A single bucket has

  • Four entries - For storing four MAC Id’s
  • Four ageing counters - One associated with each entry
  • Number of Entries - A value which tells how many entries are there in the bucket.

A single table has

  • 256 buckets
  • Total number of entries - Sum of entries in all the buckets
  • Port State - A table has three states
    • Learning - This is the default state. All actions are permitted
    • Not Learning - No new addresses are learnt. Deletions possible.
    • Locked - No additions/deletions allowed

Collisions are handled using ageing counters, one ageing counter is associated with each of the 4 entries inside a bucket. It tells the module which entries are old and which ones are new.

6.9.2.4.8.2. API Guide & Data Structures

A learning table has the following structure

typedef struct HashTable_t{

 uint32_t totalNumEntries;        /**Total number of entries in the hash table*/
 portState state;             /**State of the hash table, see enum portState above*/
 HashBucket_t  entries[NUMBUCKETS];  /**Number of bucket entries*/

} HashTable_t;

The individual bucket which makes up the learning table has the following structure

typedef struct {

 MAC mac[MAX_NUM_ENTRIES];            /**Four MAC Id per bucket*/
 uint8_t timerCount[MAX_NUM_ENTRIES]; /**Timer count used for ageing and conflict resolution*/
 uint8_t numEntries;                  /**Number of MAC entries in the bucket, 4 means it is full*/

} HashBucket_t;

The default values are

  • NUMBUCKETS 256
  • MAX_NUM_ENTRIES 4

The algorithm assumes these values and they cannot be changed at present.

API descriptions are only for information, developers are requested to use corresponding IOCTL calls. The IOCTL command for Learning/FDB modules is *ICSS_EMAC_IOCTL_LEARNING_CTRL*

*Adding A MAC address* : The corresponding API for this is

void updateHashTable(uint8_t* macId, uint8_t portNum, HashTable_t *tablePtr,ICSSEMAC_CallBackConfig* exceptionCallBack)

The API is integrated inside ICSS_EmacRxPktGet so developer need not call it separately, if at all it is required please use the IOCTL call for this. IOCTL Param value is ICSS_EMAC_LEARN_CTRL_UPDATE_TABLE

*Looking up an Entry* : The corresponding API for this is

uint8_t findMAC(const uint8_t * macId, HashTable_t *tablePtr)

Integrated with driver inside ICSS_EmacTxPacket, use IOCTL Param value ICSS_EMAC_LEARN_CTRL_FIND_MAC

*Removing a MAC address* : The corresponding API for this is

uint8_t removeMAC(uint8_t * macId, HashTable_t *tablePtr)

Entries are removed automatically upon ageing, if forced removal is required use IOCTL Param value ICSS_EMAC_LEARN_CTRL_REMOVE_MAC

*Ageing an Entry* : The driver already implements this inside the periodic task which is called every 100 NDK Ticks *_HwPktPoll()* but users can call it as well. IOCTL Param value ICSS_EMAC_LEARN_CTRL_INC_COUNTER

The corresponding API for this is

void incrementCounter(HashTable_t *tablePtr)

*Removing an Aged Entry* : The corresponding API for this is

void ageingRoutine(uint8_t portNum, HashTable_t *tablePtr)

Integrated with driver. IOCTL Param value ICSS_EMAC_LEARN_CTRL_AGEING

*Changing Port State* : Change the port state to appropriate value. This is useful in the implementation of requirements specified by IEEE 802.1D.

The corresponding API for this is

void changePortState(portState state, HashTable_t *tablePtr)

As part of changing port state the module implements locking of a port (where addition/deletion of entries is not possible), ageing (age the entries to simulate passage of time). Not integrated with driver, application must do it. IOCTL Param value ICSS_EMAC_LEARN_CTRL_SET_PORTSTATE

*Flushing/Clearing the entire Table* : The corresponding API for this is

void purgeTable(uint8_t portNum, HashTable_t *tablePtr)

Not integrated with driver, call separately using IOCTL Param value ICSS_EMAC_LEARN_CTRL_CLR_TABLE

6.9.2.4.8.3. Usage

The module is integrated with the driver so a developer need not bother about calling the API’s separately in the application unless there is a specific need to

  • Add a MAC ID
  • Remove a MAC ID
  • Lock the Port or change it’s state

The ageing module is called inside _HwPktPoll (which is a periodic NDK task, more info in the porting guide) via an IOCTL call, to age faster please call the routine separately in another task. Changing the time period of _HwPktPoll is not recommended as many other tasks are performed in this.

6.9.2.4.9. Storm Control

Strom control or Storm prevention is a feature that limits the number of broadcast and multicast packets going to the host and/or cutting through to the other port. Since broadcast and multicast packets are sent over all the ports of a switch they have the potential to create a storm which drowns all other traffic on the network, in this regard this is a very important feature for the switch.

6.9.2.4.9.1. Design

Storm prevention is implemented on the two PRU’s as a credit based scheme. When the feature is enabled, every time a multicast or broadcast packet is received a counter referred to as storm prevention credits is decremented and the packet is sent to the host as well as cut through. If the counter value is 0 then the packet is dropped. The counter is stored on respective PRU DMEM’s and is reset after a fixed period by the Host. The combination of this period and credit value decides the rate of acceptance/rejection.

The mechanism is shown below in the diagram

../_images/Storm_Prevention_architecture_Industrial.jpeg

The Storm prevention implementation is similar in both PRU’s but implemented separately, so it’s possible to turn it off selectively for each port. As of now the multicast and broadcast storm prevention functionalities are clubbed together but it is proposed to have them separate in the future.

6.9.2.4.9.2. API Guide & Data Structures

The main parent structure for Storm Prevention is

typedef struct {

 uint8_t suppressionEnabled;   /** enable/disable storm prevention*/
 uint16_t credits;             /** Number of packets allowed in a time interval*/

} stormPrevention_t;

There is an instance of this structure for each port

API descriptions are only for information, developers are requested to use corresponding IOCTL calls. The IOCTL command for Learning/FDB modules is *ICSS_EMAC_IOCTL_STORM_PREV_CTRL*

*Enabling Storm Prevention*  : The corresponding API for this is

void ICSS_EmacEnableStormPrevention(uint8_t portnum, ICSSEMAC_Handle icssEmacHandle)

Corresponding IOCTL Param value is ICSS_EMAC_STORM_PREV_CTRL_ENABLE

*Disabling Storm Prevention* : Similar to enablement, variable set to False. The corresponding API for this is

void ICSS_EmacDisableStormPrevention(uint8_t portnum, ICSSEMAC_Handle icssEmacHandle)

IOCTL Param value is ICSS_EMAC_STORM_PREV_CTRL_DISABLE

*Resetting the counters* : This is called inside _HwPktPoll which is the NDK tick function. The time period of this tick function (default 100ms) in combination with credits value decides the rate at which Storm Prevention works. This is called by default inside the driver.

The corresponding API for this is

void ICSS_EmacResetStormPreventionCounter(ICSSEMAC_Handle icssEmacHandle)

IOCTL Param value is ICSS_EMAC_STORM_PREV_CTRL_RESET

*Changing the rate* : To change how many packets are accepted or rejected change the value in the structure. At every iteration these values are written to the data RAM by the ICSS_EmacResetStormPreventionCounter API. The scheme through which this occurs is explained in the design description above

The corresponding API for this is

void setCreditValue(uint16_t creditValue, stormPrevention_t* stormPrevPtr)

IOCTL Param value is ICSS_EMAC_STORM_PREV_CTRL_SET_CREDITS

6.9.2.4.9.3. Usage

Most often Storm Prevention is the main reason for users not being able to receive a packet, esp if the rate is configured incorrectly. So first verify if it is enabled for that port. This can be done by

  • Checking structure variable : See the value of suppressionEnabled variable in the structure.
  • Checking memory : See the memory offset STORM_PREVENTION_OFFSET in the corresponding data RAM. The first bit of the byte location tells you whether the logic is enabled on the port.
  • Disabling Storm Prevention : This is the easiest and preferable for someone not using an emulator. Use the corresponding IOCTL call.

To quickly verify if the logic is indeed dropping packets, try sending some broadcast packets at line rate to the device and check the value of PRU statistics variable stormPrevCounter. See statistics section on how to read this variable.

6.9.2.4.10. Statistics

Statistics on ICSS Switch provide a great deal of information on what’s going on with the switch. They are enabled by default and provide provide port specific statistics. They are also a great debugging tool and should be the first thing a developer should look at if they suspect any issue with Rx or Tx.

6.9.2.4.10.1. Design

The Statistics are divided into

  • *Statistics on PRU* : Since the LLD functionality is implemented on the PRU’s the majority of statistics are implemented on them. The count for each port is stored on the respective Data RAM’s starting at the offset STATISTICS_OFFSET. The map is shown below
  • *Statistics on Host* : The packets coming to the Host are counted once again, this is useful for debugging purposes and to measure throughput (from the PRU to Host) if required. Some statistics like “Unknown protocol type” are only implemented on the Host.

Functionally the statistics are classified into

  • *Rx/Tx related statistics* : This includes count of broadcast, multicast and unicast packets and their derivatives. Only valid packets are part of this which means that an Rx packet which has been dropped because of storm prevention will not be counted.
  • *Error Counters* : This includes statistics such as Dropped frames, Rx/Tx errors etc.
  • *Other statistics* : Includes statistics related to 802.1 CSMA/CD, number of link breaks etc.

A description of PRU statistics along with corresponding memory map is given below.

align=”center” *PRU Statistics Description & Memory Map* Name of Variable

Description

Name of Offset

Refer to icss_emacSwitch.h

Offset in PRU DRAM 0/1

txBcast

Number of broadcast packets sent

TX_BC_FRAMES_OFFSET

0x1F00

txMcast

Number of multicast packets sent

TX_MC_FRAMES_OFFSET

0x1F04

txUcast

Number of unicast packets sent

TX_UC_FRAMES_OFFSET

0x1F08

txOctets

Total number of octets sent, includes all packets

TX_BYTE_CNT_OFFSET

0x1F0C

rxBcast

Number of broadcast packets received

RX_BC_FRAMES_OFFSET

0x1F10

rxMcast

Number of multicast packets received

RX_MC_FRAMES_OFFSET

0x1F14

rxUcast

Number of unicast packets received

RX_UC_FRAMES_OFFSET

0x1F18

rxOctets

Total number of octets received, includes all packets

RX_BYTE_CNT_OFFSET

0x1F1C

lateColl

Number of packets that suffered collisions late into Tx

LATE_COLLISION_OFFSET

0x1F20

singleColl

Number of packets that suffered collision only once

SINGLE_COLLISION_OFFSET

0x1F24

multiColl

Number of packets that suffered collisions more than once

MULTIPLE_COLLISION_OFFSET

0x1F28

excessColl

Number of packets that suffered collisions more than 15 times

EXCESS_COLLISION_OFFSET

0x1F2C

txOverFlow

Number of times Tx queue overflowed

(This is not supported right now)

TX_OVERFLOW_OFFSET

0x1F30

rxMisAlignmentFrames

Number of frames with uneven number of bytes in an octet

(This is not tested)

RX_MISALIGNMENT_COUNT_OFFSET

0x1F34

stormPrevCounter

Number of packets dropped due to storm prevention

STORM_PREVENTION_COUNTER

0x1F38

macRxError

Number of packets with Rx MAC Error

RX_ERROR_OFFSET

0x1F3C

SFDError

Number of packets with incorrect SFD

SFD_ERROR_OFFSET

0x1F40

defTx

Number of packets deferred at least once due to CS high signal

TX_DEFERRED_OFFSET

0x1F44

macTxError

Number of packets facing Tx MAC Error

TX_ERROR_OFFSET

0x1F48

rxOverSizedFrames

Number of packets >1518 bytes

RX_OVERSIZED_FRAME_OFFSET

0x1F4C

rxUnderSizedFrames

Number of packets < 60 bytes

RX_UNDERSIZED_FRAME_OFFSET

0x1F50

rxCRCFrames

Frames with CRC/FCS Error

RX_CRC_COUNT_OFFSET

0x1F54

droppedPackets

Number of Received packets that were not transmitted because of link loss

RX_DROPPED_FRAMES_OFFSET

0x1F5C

tx64byte

Transmitted frames with size <= 64 bytes

TX_64_BYTE_FRAME_OFFSET

0x1F60

tx65_127byte

Transmitted frames with size >= 65 bytes and <= 127 bytes

TX_65_127_BYTE_FRAME_OFFSET

0x1F64

tx128_255byte

Transmitted frames with size >= 128 bytes and <= 255 bytes

TX_128_255_BYTE_FRAME_OFFSET

0x1F6C

tx256_511byte

Transmitted frames with size >= 256 bytes and <= 511 bytes

TX_256_511_BYTE_FRAME_OFFSET

0x1F70

tx512_1023byte

Transmitted frames with size >= 512 bytes and <= 1023 bytes

TX_512_1023_BYTE_FRAME_OFFSET

0x1F74

rx64byte

Received frames with size <= 64 bytes

RX_64_BYTE_FRAME_OFFSET

0x1F78

rx65_127byte

Received frames with size >= 65 bytes and <= 127 bytes

RX_65_127_BYTE_FRAME_OFFSET

0x1F7C

rx128_255byte

Received frames with size >= 128 bytes and <= 255 bytes

RX_128_255_BYTE_FRAME_OFFSET

0x1F80

rx256_511byte

Received frames with size >= 256 bytes and <= 511 bytes

RX_256_511_BYTE_FRAME_OFFSET

0x1F84

rx512_1023byte

Received frames with size >= 512 bytes and <= 1023 bytes

RX_512_1023_BYTE_FRAME_OFFSET

0x1F88

6.9.2.4.10.2. API Guide & Data Structures

As discussed above there are two data structures for Statistics.

  1. PRU based
  2. On Host

Shown below are the members of Host Statistics. The members of PRU statistics are listed in the memory map.

typedef struct {

 volatile uint32_t txUcast;         /**Number of unicast packets sent*/
 volatile uint32_t txBcast;         /**Number of broadcast packets sent*/
 volatile uint32_t txMcast;         /**Number of multicast packets sent*/
 volatile uint32_t txOctets;            /**Number of bytes sent*/
 volatile uint32_t rxUcast;         /**Number of unicast packets rcvd*/
 volatile uint32_t rxBcast;         /**Number of broadcast packets rcvd*/
 volatile uint32_t rxMcast;         /**Number of multicast packets rcvd*/
 volatile uint32_t rxOctets;            /**Number of Rx packets*/
 volatile uint32_t rxUnknownProtocol;           /**Number of packets with unknown protocol*/
 volatile uint32_t linkBreak;           /**Number of link breaks*/

}hostStatistics_t;

As one can see most of the members are identical to that of PRU statistics (they are a subset) and if all packets are sent to the Host then these member values for PRU and Host statistics should match.

API descriptions are only for information, developers are requested to use corresponding IOCTL calls. The IOCTL command for Statistics module is *ICSS_EMAC_IOCTL_STATS_CTRL*

*Reading PRU Statistics*  : To fetch PRU statistics an M2M copy is done from the PRU Data RAM to the PRU statistics structure on DDR. To get the values correctly the memory layout on both sides should be identical. Developers should not modify the member order in pruStatistics_t. Doing so can give incorrect results

Host statistics are updated on the fly in the structure as packets are received (ICSS_EmacUpdateRxStats) or transmitted (ICSS_EmacUpdateTxStats) so there is no separate API to collate them.

The corresponding API for this is

void ICSS_EmacReadStats(uint8_t portNum, ICSSEMAC_Handle icssEmacHandle)

IOCTL Param value is ICSS_EMAC_IOCTL_STAT_CTRL_GET

*Clearing PRU and Host Statistics*  : To clear the values do memory write to the structure memory, PRU data RAM and initialize to 0.

The corresponding API for this is

void PurgeStats(uint8_t portNum, ICSSEMAC_Handle icssEmacHandle)

IOCTL Param value is ICSS_EMAC_IOCTL_STAT_CTRL_CLEAR

6.9.2.4.10.3. Usage

Statistics are a great tool to debug issues on the switch. To get them in the application use the IOCTL calls to get and clear statistics

While IOCTL calls provide access to statistics in the application. If someone is using CCS then another quick way to see if there is any activity on the Ports is to directly go to the PRU data RAM offset STATISTICS_OFFSET and see the values directly in memory Refer Debug guide on how to see data RAM values directly in CCS.

6.9.2.5. Memory Map

The memory map here refers to the Shared Data RAM memory map in ICSS. L3 map is not of much use to the developer while DDR map is dynamic and is part of the application. The goal of providing this is to help the developer in debugging. Based on the memory map one can directly look at the memory in a CCS + Emulator environment and verify if driver/firmware is working correctly.

The memory map can be found in icss_emacSwitch.h under os_drivers/lld/emac and is common to firmware and driver builds

Table 6.6 *ICSS Shared Memory Map*
Shared Memory Offset Value PRU0 Data RAM Value PRU1 Data RAM Value
0x0000 - 0x1C10 Buffer Descripto r Offsets For Host Queues 0x0000 - 0x0400 Reserved for Future Use 0x0000 - 0x0400 Reserved for Future Use
0x1C10-0x 2010 Multicast Filtering Table (Disabled for EMAC) 0x0400-0x 1EC0 Available for Protocol/ Applicati on 0x0400-0x 1EC0 Available for Protocol/ Applicati on
0x2010-0x 2400 Reserved for Future Use 0x1EC0-0x 1F00 Port Queue Offsets 0x1EC0-0x 1F00 Port Queue Offsets
0x2400-0x 3000 Available for Protocol/ Applicati on 0x1F00-0x 1F8C Port0 Statistic s (Map provided above _) 0x1F00-0x 1F8C Port1 Statistic s (Map provided above _)
    0x1F8C Port0 Storm Preventio n Control Variable 0x1F8C Port1 Storm Preventio n Control Variable
    0x1F90

Port0 Link Speed 0x64 - 100Mbps

0xA - 10Mbps

0x1F90

Port1 Link Speed Same as Port0

Any other value is illegal

    0x1F94

Port0 Link Status 0x1 - Link Up

0x0 - Link Down

0x1F94 Port1 Link Status Same as Port0
    0x1F9A

Port0 Control 0x1 - Rx Disabled

0x0 - Rx Enabled

0x1F9A Port1 Control Same as Port0
    0x1FA0 Port0 MAC ID 6 bytes 0x1FA0 Port1 MAC ID 6 bytes

6.9.2.6. OS and TCP/IP

6.9.2.6.1. RTOS

The SDK uses SYS/BIOS as it’s RTOS. Configuration for the RTOS is done through RTSC tool chain integrated with CCS. SYS/BIOS is provided free of cost and is a very capable RTOS for typical use cases with minimal latency.

The driver is written in a manner such that there is very little dependency on the Operating System. All dependence on SYS/BIOS is abstracted to OSAL (Operating System Abstraction Layer) and developers are integrate their own operating systems.

OSAL consists of

  1. Interrupt management
  2. Task and Semaphore management, Mailbox
  3. Management of peripherals like DMTimer, BIOS Timers

The osdrv layer deals with RTOS and other OS related tasks in general, within this layer the relevant files which deal with OSAL layer are *osdrv_osal.c* and *osdrv_osal.h*. Developers are requested to port the API’s within these two files to their own Operating System.

6.9.2.6.2. TCP/IP

The Industrial SDK uses NDK as it’s TCP/IP stack. API reference guide here. Like SYS/BIOS the module is imported externally through RTSC (refer Debug Guide) and managed through the application configuration file (*am335x_app.cfg* and *am437x_app.cfg*)

NDK recommends it’s own abstraction layer which is called NIMU (Network Interface Management Unit). This layer is implemented in the driver. Relevant source files are

  • icss_ethdriver.c
  • icss_nimu_eth.c
  • icss_switch_emac.c

Understanding the NIMU layer helps in porting another TCP/IP stack to the example. The NIMU layer is explained in this guide

Porting guide covers all aspects of using a custom TCP/IP stack to the EMAC LLD example.

6.9.2.7. PRUSS & EMAC Handle

The ICSS EMAC Handle is a main driver handle which provides access to all members, variables, registers and addresses in the SoC.

It is the application’s task to allocate memory for the handle and pass it to the driver initialization API. The handle is also required as a parameter for most of the external API’s and all IOCTL calls in the driver so it’s important to understand it’s members.

The members of the EMAC Handle are discussed in detail here

The sample code for Handle allocation and initialization (from the example application) is shown below

/*Declare the EMAC Handle*/
ICSSEMAC_Handle emachandle;
/*Declare the PRUSS Handle*/
PRUICSS_Handle handle;
/*Allocate memory for EMAC and PRUSS Handle*/
handle = (PRUICSS_Handle)malloc(sizeof(PRUICSS_Config));
handle->object = (PRUICSS_V1_Object*)malloc(sizeof(PRUICSS_V1_Object));
handle->hwAttrs = (PRUICSS_HwAttrs*)malloc(sizeof(PRUICSS_HwAttrs));
emachandle = (ICSSEMAC_Handle)malloc(sizeof(ICSSEMAC_Config));
/*Initialize the EMAC*/
ICSSEmacDRVInit(emachandle, 0);
/*Initialize PRUSS*/
PRUSSDRVInit(handle); /* ICSS_M instance 0 */
/*Assign PRU handle to EMAC handle making it the parent structure*/
((ICSSEMAC_Object*)emachandle->object)->pruIcssHandle = handle;
((ICSSEMAC_Object*)emachandle->object)->emacInitcfg = switchEmacCfg;

6.9.2.8. IOCTL

IOCTL implementation for the switch drivers is identical to the Unix/Linux based IOCTL calls. They provide the application a convenient method to access driver/kernel space parameters or modify them.

Developers are expected to familiarize themselves with the full list of IOCTL calls so that they can utilize all the features provided. This is even more important when working in an Application/OS kind of environment where access to an emulator is not available.

6.9.2.8.1. Design

The primary IOCTL call is through the API ICSS_EmacIoctl which is implemented in the file icss_emacFwInit.c An IOCTL call uses two parameters to find out which driver API to call

  1. ioctlCommand : Is used to locate the module (Statistics/ Port control etc) which should be called.
  2. ioctlParams : Is used to give module specific instructions

*ioctlParams* consists of

  • command : Indicates which specific API to execute
  • ioctlVal : Sometimes the API may require specific input, this is used to provide that.

For example to disable receive functionality on a port the following code is used. This code is part of Link interrupt functionality where receive is disabled when PHY detects a link down.

ioctlvalue = ICSS_EMAC_IOCTL_PORT_CTRL_DISABLE;
ioctlParams.ioctlVal = &ioctlvalue;
ICSS_EmacIoctl(icssEmacHandle, ICSS_EMAC_IOCTL_PORT_CTRL, ICSS_EMAC_PORT_1, (void*)&ioctlParams);

Here ICSS_EMAC_IOCTL_PORT_CTRL refers to the *ioctlCommand* while ICSS_EMAC_IOCTL_PORT_CTRL_DISABLE is the *command* part of ioctlParams which tells which action to perform, in this case disabling the port. Port selected is ICSS_EMAC_PORT_1 which refers to Port 1.

A complete list of commands and actions is given below.

6.9.2.8.2. API Guide & Data Structures

IOCTL Command structure

typedef struct ICSSEMAC_IoctlCmd {
  uint8_t command;
  uint8_t* ioctlVal;
}ICSSEMAC_IoctlCmd;

There is only one API for IOCTL. It’s defined below

uint8_t ICSS_EmacIoctl(ICSSEMAC_Handle icssEmacHandle, uint32_t ioctlCommand, uint8_t portNo, void *ioctlParams)

The possible values for *ioctlCommand* are

  • ICSS_EMAC_IOCTL_PORT_CTRL : Select Port Control Operations. Enable/Disable Rx for the specified port.
  • ICSS_EMAC_IOCTL_LEARNING_CTRL : Select Learning/FDB module.
  • ICSS_EMAC_IOCTL_STORM_PREV_CTRL : Select Storm Prevention module.
  • ICSS_EMAC_IOCTL_STATS_CTRL : Select Statistics module.
  • ICSS_EMAC_IOCTL_TTS_CTRL : Select Time Triggered Send Configuration module. Enable/Disable TTS for the specified port.
  • ICSS_EMAC_IOCTL_TTS_STATUS_CTRL : Select Time Triggered Send Query module. Get TTS status and other details for the specified port from PRU firmware.

Possible values for *ioctlParams* are

  • ICSS_EMAC_IOCTL_LEARNING_CTRL : Refer to Learning/FDB API’s
    • ICSS_EMAC_LEARN_CTRL_UPDATE_TABLE : Add an entry to the Hash table.
    • ICSS_EMAC_LEARN_CTRL_CLR_TABLE : Clear the Learning Table for the specified port.
    • ICSS_EMAC_LEARN_CTRL_AGEING : Age out old entries from the table.
    • ICSS_EMAC_LEARN_CTRL_FIND_MAC : Find the port number given a MAC ID.
    • ICSS_EMAC_LEARN_CTRL_REMOVE_MAC : Remove a MAC ID from the Learning Table
    • ICSS_EMAC_LEARN_CTRL_INC_COUNTER : Age the entries with time by calling this periodically
    • ICSS_EMAC_LEARN_CTRL_INIT_TABLE : Initialize the learning table
    • ICSS_EMAC_LEARN_CTRL_SET_PORTSTATE : Set the Port state to value defined by the enum type portState
  • ICSS_EMAC_IOCTL_STATS_CTRL : Refer to Statistics API’s
    • ICSS_EMAC_IOCTL_STAT_CTRL_GET : Get the statistics
    • ICSS_EMAC_IOCTL_STAT_CTRL_CLEAR : Clear all stat counters
  • ICSS_EMAC_IOCTL_STORM_PREV_CTRL : Refer to Storm prevention API’s
    • ICSS_EMAC_STORM_PREV_CTRL_ENABLE : Enable Storm Prevention
    • ICSS_EMAC_STORM_PREV_CTRL_DISABLE : Disable Storm Prevention
    • ICSS_EMAC_STORM_PREV_CTRL_SET_CREDITS : Set how many BC/MC packets are allowed in a period of 100 NDK Ticks (Time period of _HwPktPoll())
    • ICSS_EMAC_STORM_PREV_CTRL_INIT : Initialize Storm Prevention
    • ICSS_EMAC_STORM_PREV_CTRL_RESET : Renew the storm prevention counters, this allows more packets to come through once existing credits have expired. This must be called periodically in _HwPktPoll()
  • ICSS_EMAC_IOCTL_PORT_CTRL : For Rx Enable/Disable operations. There are no sub-commands here. Whether to enable or disable is decided by the value of *ioctlVal*
6.9.2.8.3. Usage

Using IOCTL to debug the issues is encouraged. This is easier than trying to connect an emulator and reading the values at run time. There are numerous instances of it’s usage. A quick search for the API ICSS_EmacIoctl throughout the code reveals numerous examples. One of them pertaining to Storm Control module is shown below.

In this example the storm prevention counters are reset in PRU Data RAM using IOCTL. The if/else refers to Switch or EMAC mode, rest of the code is self-explanatory

ioctlParams.command = ICSS_EMAC_STORM_PREV_CTRL_RESET;
/*Reset the credit values used for Storm prevention*/
if(ICSS_EMAC_MODE_SWITCH == ((ICSSEMAC_Object*)(pi->nimuDrvHandle)->object)->emacInitcfg->portMask)
{
  strmPreventionEnable1 = (stormPrevention_t*)(((ICSSEMAC_Object*)(pi->nimuDrvHandle)->object)->stormPrevPtr);
  strmPreventionEnable2 = (stormPrevention_t*)(((ICSSEMAC_Object*)(pi->nimuDrvHandle)->object)->stormPrevPtr +1);
  if(strmPreventionEnable1->suppressionEnabled ||   strmPreventionEnable2->suppressionEnabled)
   ICSS_EmacIoctl(pi->nimuDrvHandle, ICSS_EMAC_IOCTL_STORM_PREV_CTRL, NULL, (void*)&ioctlParams);
}
else
{
  strmPreventionEnable1 = (stormPrevention_t*)(((ICSSEMAC_Object*)(pi->nimuDrvHandle)->object)->stormPrevPtr);
  if(strmPreventionEnable1->suppressionEnabled)
   ICSS_EmacIoctl(pi->nimuDrvHandle, ICSS_EMAC_IOCTL_STORM_PREV_CTRL, NULL, (void*)&ioctlParams);
}

6.9.2.9. Time Triggered Send

The EMAC Time Triggered Send (TTS) is used to expand classical Ethernet to meet deterministic, time-critical or safety-relevant conditions. TTS reduces the transmission jitter from 10us range to 40ns. TTS can be dynamically enabled and disabled by the Host. We have two well defined TTS APIs which control all TTS related EMAC aspects. Developers are advised to access these APIs using the EMAC IOCTL implementation as explained in the IOCTL section previously.

6.9.2.9.1. TTS Design Overview

TTS is designed to facilitate transmission of packets at pre-defined cyclic instants/triggers. The TTS API Details and Data Structures are explained below but in a broad sense we can say that while initializing TTS, the application must provide the first cyclic trigger and the cycle period. The PRU firmware then sets cyclic triggers repeatedly and shall send the packets cyclically provided that they are queued before the trigger. The following timing diagram explains the use of TTS.

Each cycle shall have a configuration time (as shown in the figure above) before each trigger. This configuration time is used to setup the start trigger and end trigger of current cycle in the PRU firmware. If the application does not set a suitable (long enough) configuration time, the PRU and perhaps even the EMAC Driver TTS API may not get enough time to setup and initialize TTS. This might result in improper functionality. The configuration time shall also be provided during initialization and shall be application specific. For example, if a response packet is to be received for the cyclic packet sent at trigger T1 and based on that response packet the next cyclic packet shall be generated, then the developer can increase/decrease configuration time accordingly to ensure that the next cyclic packet is ready before trigger T2 which shall in-turn be based on when the response packet is received.

Queue 0 (high priority queue) is reserved as the real-time queue. All packets in queue 0 are cyclic packets. On the other hand, packets from other queues are acyclic packets. Cyclic packets are sent at triggered instances, whereas acyclic packets are sent based on time availability, as shown in the figure below.

The time availability check for cyclic packets means to basically check whether the acyclic packet can be transmitted such that its transmission does not overlap the next cyclic trigger, considering the size of the acyclic packet. Such a situation is represented as “Undesired Behaviour” in the above figure and PRU firmware ensures that this never happens. Only one cyclic packet will be sent out in each cycle irrespective of the number of cyclic packets available in Queue 0. There is no restriction on the number of acyclic packets sent out in each cycle but it is contingent on time availability. Cyclic packets must be queued in Queue 0 before the trigger instant else two erroneous situations are possible:

  1. If the firmware finds a packet in any other low priority queue, it will send the acyclic packet. Once an acyclic packet has been transmitted in a given cycle, no cyclic packet will be transmitted in that cycle. So, if the cyclic packet is not queued on time, it will miss the cycle and will be transmitted in the next cycle.
  2. If all the queues are empty and a cyclic packet is inserted late, it will result in increased jitter.

The above two situations are demonstrated in the figure below.

In the above figure, the PRU firmware ensures that the first two situations never occur but the application needs to take care of the third situation, i.e., by queueing the cyclic packet on time.

The PRU firmware makes the following assumptions regarding TTS:

  1. The cycle period is long enough to be able to transmit any cyclic packet in queue 0. Failure to ensure this will cause the cyclic packet with size greater than the allowed size (as per the period), and any cyclic packets following it, to remain in the queue.
  2. The configuration time provided (using ICSS EMAC IOCTL) is sufficient for the PRU to configure the next cycle. PRU should typically need a maximum of 10us to configure the next cycle.
  3. If the host keeps queuing packets irrespective of the fact whether the packet has been transmitted by the firmware (in accordance with the preset triggered intervals), the packets might get dropped at the driver level if the queue is full. It is assumed that this is taken care of at the host level.
6.9.2.9.2. TTS API Details and Data Structures

TTS has the following APIs, which are accessed using EMAC IOCTL implementation as explained in the IOCTL section previously.

int8_t ICSS_EmacTTS(const ICSS_EmacTTSConfig* ttsConfig)

This API is used to enable/disable time triggered send for Queue 0 frames.

int8_t ICSS_EmacTTSGetStatus(ICSS_EmacTTSQuery* ttsQuery)

This API is used to query time triggered send details, status and TTS parameter values from PRU firmware.

The TTS parameter structure is explained below:

typedef struct ICSS_EmacTTSConfig_s {
  ICSSEMAC_Handle icssEmacHandle;
  uint8_t portNumber;
  uint64_t cycleStartTime;
  uint32_t cyclePeriod;
  uint32_t configTime;
  uint8_t statusTTS;
  uint8_t cycTxSOFStatus;
} ICSS_EmacTTSConfig;
  • icssEmacHandle: EMAC handle for concerned EMAC instance and port.
  • portNumber: Port number for which TTS needs to be enabled/disabled.
  • cycleStartTime: A future IEP counter value at which the first cyclic packet will be transmitted.
  • cyclePeriod: TTS cycle period.
  • configTime: Configuration time for PRU to setup upcoming TTS cycle.
  • statusTTS: Enable/Disable TTS. Enable = 1, Disable = 0.
  • cycTxSOFStatus: Enable/Disable storing transmit start-of-frame timestamp for cyclic packets in memory. Enable = 1, Disable = 0.

The TTS query structure is as explained below:

typedef struct ICSS_EmacTTSQuery_s {
  ICSSEMAC_Handle icssEmacHandle;
  uint8_t portNumber;
  uint8_t statusTTS;
  uint8_t missedCycle;
  uint8_t insertCycFrameNotification;
  uint8_t cycTxSOFStatus;
  uint32_t missedCycleCounter;
  uint64_t cycTxSOF;
} ICSS_EmacTTSQuery;
  • icssEmacHandle: EMAC handle for concerned EMAC instance and port.
  • portNumber: Port number for which TTS query needs to be performed.
  • statusTTS: Whether TTS is enabled/disabled for given port. Enabled = 1, Disabled = 0.
  • missedCycle: Whether any cyclic packet missed a cycle. Missed = 1, Did not miss = 0.
  • insertCycFrameNotification: Notification to state that it’s time to insert cyclic packet. If it’s time = 1, else = 0.
  • cycTxSOFStatus: Whether storing transmit start-of-frame timestamp for cyclic packets in memory is enabled/disabled. Enabled = 1, Disabled = 0.
  • missedCycleCounter: Number of cycles missed by cyclic packets.

The application shall update the elements of the ICSS_EmacTTSConfig structure and pass its pointer to EMAC IOCTL with appropriate command to enable/disable TTS. On the other hand, the application shall only update the icssEmacHandle and portNumber elements of the ICSS_EmacTTSQuery structure and pass its pointer to EMAC IOCTL with appropriate command to retrieve the details from PRU firmware. The driver TTS API (ICSS_EmacTTSGetStatus) shall then update the elements of the structure with appropriate values.

TTS can be enabled/disabled using EMAC IOCTL as follows:

For Enable:

ICSSEMAC_IoctlCmd ioctlParams;
ICSS_EmacTTSConfig ttsConfig;
uint32_t iepRegsBase;
int8_t ret;

ioctlParams.command = 0;
ioctlParams.ioctlVal = (void *)(&ttsConfig);

ttsConfig.icssEmacHandle = icssEmacHandle;
ttsConfig.cycTxSOFStatus = ICSS_EMAC_TTS_CYC_TXSOF_ENABLE;
ttsConfig.portNumber = portNumber;
ttsConfig.configTime = ICSS_EMAC_TTS_CONFIG_TIME;
ttsConfig.cyclePeriod = cyclePeriod;
ttsConfig.statusTTS = ICSS_EMAC_TTS_ENABLE;

iepRegsBase = (((ICSS_EmacHwAttrs*)icssEmacHandle->hwAttrs)->emacBaseAddrCfg)->prussIepRegs;

/*  Reading IEP Counter Value.  */
iepCounterVal = (*((uint64_t*)(iepRegsBase + CSL_ICSSIEP_COUNT_REG0)));

/*  Calculating cycle start value by adding 100us to counter value. */
ttsConfig.cycleStartTime = (uint64_t)(iepCounterVal + 100000);

/*  Enabling time triggered send.   */
ret = ICSS_EmacIoctl(icssEmacHandle, ICSS_EMAC_IOCTL_TTS_CTRL, portNumber, &ioctlParams);
assert(ret == 0);

For Disable:

ICSSEMAC_IoctlCmd ioctlParams2;
ICSS_EmacTTSConfig ttsConfig;
int8_t ret;

/*  Setting tts status to disable (Port 1)  */
ttsConfig.icssEmacHandle = icssEmacHandle;
ttsConfig.statusTTS = ICSS_EMAC_TTS_DISABLE;
ttsConfig.cyclePeriod = 0;
ttsConfig.configTime = 0;
ttsConfig.cycleStartTime = 0;
ttsConfig.cycTxSOFStatus = ICSS_EMAC_TTS_CYC_TXSOF_DISABLE;
ttsConfig.portNumber = portNumber;

ioctlParams2.command = 0;
ioctlParams2.ioctlVal = (void *)(&ttsConfig);

/*  Disabling time triggered send on PORT 1 (PRU0). */
ret = ICSS_EmacIoctl(icssEmacHandle, ICSS_EMAC_IOCTL_TTS_CTRL, portNumber, &ioctlParams2);
assert(ret == 0);
6.9.2.9.3. TTS Cyclic Frame Notification

The PRU firmware has been designed to notify the Host when it’s time to insert the cyclic packet. This helps the Host to queue the cyclic packet well before trigger time and avoid any unnecessary jitter or any other erroneous situations as mentioned previously. The firmware does this in two ways:

6.9.2.9.3.1. Polling Mode
  • In this mode the firmware sets a status bit when it’s time to insert the cyclic frame and this bit cleared when the time to insert the cyclic frame is over or the firmware has found a cyclic frame in Queue 0.
  • This status bit can be queried using the EMAC IOCTL and is reflected in insertCycFrameNotification element of the ICSS_EmacTTSQuery structure.
  • If it’s time, insertCycFrameNotification = 1, else insertCycFrameNotification = 0.
  • The application must then continuously poll for this status by repeating EMAC IOCLT calls and querying TTS status.
  • Once insertCycFrameNotification = 1, the application must queue the cyclic frame in Queue 0.
6.9.2.9.3.2. Interrupt Mode
  • In this mode, in addition to setting the status bit as in polling mode, the firmware has the capability to give an interrupt to the Host when it’s time to insert a cyclic frame.
  • The interrupt feature should be first enabled as follows during EMAC Driver Initilization.
ICSS_EmacInitConfig* switchEmacCfg;
switchEmacCfg = (ICSS_EmacInitConfig*)malloc(sizeof(ICSS_EmacInitConfig));
switchEmacCfg->ICSS_EmacTTSEnableCycPktInterrupt = ICSS_EMAC_TTS_CYC_INTERRUPT_ENABLE;
  • Also, proper interrupt mapping should be done as explained earlier in this guide.
  • Interrupt callback functions should also be registered for all concerned EMAC handles using the following API:
ICSS_EmacRegisterHwIntTTSCyc(emachandle, (ICSS_EmacCallBack)ttsCycPort1Callback);
  • Interrupts should also be enabled. Please refer to example ICSS EMAC applications from Processor SDK RTOS for further details.
  • Once the PRU firmware throws an interrupt, the registered callback function is called and this is where the application shall queue the cyclic packet to Queue 0.

6.9.2.10. ICSS EMAC LLD Dependencies

ICSS EMAC LLD is dependent on the Application/Transport layer for its proper functioning. These dependencies have been consolidated and exported to the application layer (example) to make it easy for developer to integrate the LLD with their own RTOS and TCP/IP stack.

6.9.2.10.1. Interrupt Configuration

ICSS EMAC LLD expects the Interrupt configuration to come from Application/Transport layer. The interrupt configuration is explained in detail in the interrupts section. Please refer to it for more details.

The LLD makes use of two interrupts for copying packets from the queues to the TCP/IP stack.

6.9.2.10.1.1. Rx Interrupt

The ICSS EMAC LLD depends on the Rx interrupt for receiving packets.The application should do the interrupt creation and should use the API ICSS_EmacRxInterruptHandler as the ISR.This will enable the ICSS EMAC LLD to receive packets. The user should make sure the arm interrupt (Rx) is mapped to correct PRUSS Event. The PRUSS Event that is used for Rx will be determined by the firmware which will be used along with the ICSS EMAC LLD

6.9.2.10.2. Learning module Increment counter implementation

This is required for Switch implementation only. The application needs to call the IOCTL periodically, this is already done by the NDK. Refer to the API section of Learning for more details.

6.9.2.10.3. MDIO Configurations

ICSS EMAC LLD does not do any of the MDIO configurations. It expects the application to do following MDIO operations

  • MDIO Initialization -
  • MDIO Link Interrupt enable if MDIO Link interrupt is used

NOTE: Please refer to ti/drv/icss_emac/test/src/test_mdio.c for details of how to initialize the MDIO sub-system and how to enable MDIO link interrupts. This file contains a set of MDIO test APIs which are used by the icss emac loopback unit tests.

6.9.2.11. EMAC Configuration and How To

6.9.3. Debug with ICSS-EMAC Driver

6.9.3.1. Introduction

This is a companion guide to ICSS EMAC Developer Guide, if you have not read the developer guide it’s highly suggested that you do so.

Based upon the combined experience of development team, this document covers the most obvious use cases and debug scenarios present in ICSS EMAC LLD. Frequently asked questions from E2E forums which are relevant have also been added here.

For individual protocols like Ethernet/IP, Profinet, EtherCat etc separate debugging guides are available which discuss specific use cases.

As mentioned previously in developer guide, a discussion of EMAC LLD covers most of the ethernet driver/firmware issues and goes a long way in the understanding of other industrial protocol implementations. This applies to debug guide as well.

6.9.3.1.1. Assumption

Assumptions are same as those in developer guide. A basic understanding of ICSS Architecture and SoC is assumed, some level of familiarity with Ethernet driver development is also assumed. In addition to this a basic familiarity with the following tools is also assumed.

  • Code Composer Studio
  • Any serial terminal (Putty/Tera Term)
  • Wireshark or any other packet sniffing tool
  • Any PC based tool capable of sending packets
6.9.3.1.2. Scope of the document

This document is meant to help the developer

  • Familiarize with common debugging tools and techniques
  • Identify and resolve frequently faced issues

6.9.3.2. Common Debugging Tasks

6.9.3.2.1. Loading and running on CCS

1. Connect JTAG Emulator to EVM in-case of IDK or Connect USB cable to board in-case of ICE

2. Select View->Target Configurations. Right click on the required configuration in the list and Select Launch Selected Configuration

3. Right Click on the Cortex A9/A8 listed in Debug view and select Connect. (Click View->Debug to view debug window, if not visible)

  1. Select System Reset
  2. Select Suspend
  3. Load the GEL file and execute initialization script.

7. Once the initialization is completed, Select Run->Load ->Load Program. Here browse to the required executable and click OK

8. After a successful load, the program is expected to be in suspended state and program counter is pointing to main function. If the program is not in suspended state :

  1. Suspend the application by selecting Run->Suspend
  2. Restart the application by selecting Run->Restart

9. Run the application by selecting Menu->Run->Resume. This will execute the application.

../_images/De1.png

NOTE

  • While launching a debug session for the first time, CCS will ask for

the CPU to which the program needs to be loaded. Please select Cortex-A9/A8 and continue.

  • If TeraTerm does not display an output upon program execution.

TeraTerm can be initialized just prior to program execution by performing steps 1-8 and then

Disconnect the terminal session using File -> Disconnect

Reconnect the terminal session with File -> New Connection

  • If there is a valid application in SPI or NOR flash(in their

corresponding boot mode), on “System Reset” the application loads right away. This might cause issues on the application you load via JTAG. To avoid this, put a hardware breakpoint at 0x402f_0400(in case of MMSCD boot mode) or 0x30000000(in case of qSPI boot mode) and then do a “System Reset”. You can then continue with Step 4 after this step.

6.9.3.2.2. Connecting the PRU’s
6.9.3.2.4. Checking if Receive is working

The receive path has been explained previously in the developer guide. See here. Rx issues can manifest themselves in several ways, the following table covers most of them (not exhaustively!)

Table 6.7 Receive issues and causes
Issue Probable Cause
Host not receiving Multicast/Broadcast frames Rx interrupt not configured correctly, Firmware not receiving, Storm Prevention enabled Rx is disabled
Unicast Packets (for Host)being dropped Same as above except Storm Prevention Interface MAC not configured correctly
Multicast/Broadcast frames not being forwarded Storm Prevention enabled Firmware not receiving, Rx is disabled
Unicast frames (not for Host) not being forwarded Firmware not receiving Rx is disabled
Driver receiving packets but Raw socket not receiving frames NDK issues (there is a known issue, please see below)
Packets are getting dropped Storm Prevention enabled Data is coming in too fast. See Interrupt pacing section <http://processors.wiki. ti.com/index.php/ICSS_EMAC_LLD_de velopers_guide#Interrupt_Pacing> __ to understand this behavior

The first step is to identify the exact problem, to do that please perform these steps in order.

  1. Check if Rx is disabled : It’s possible to disable Rx in firmware through IOCTL. This is controlled through a location in ICSS memory. See memory map. Check this as a very first step. It’s not a common error but it’s possible that user is invoking the IOCTL by mistake.
  2. Check if firmware is receiving packets : See statistics this and this and find out if PRU is receiving the frames. Failure to receive frames in firmware can indicate other issues like corrupted frames, link negotiation failure or PHY related issues.
  3. Check if Rx interrupt is being asserted : This can be one of the reasons why Host would not receive packets. Put a break point in ICSS_EmacRxInterruptHandler and send a single packet using any PC based tool. The ISR should get hit. Refer to this section on how to configure the interrupt properly if interrupt is not being asserted.
  4. Check if Packets are being copied in driver : If the interrupt is asserted but packets do not reach the application, check Host statistics to verify if packets are being received correctly in the driver. Refer to the sectionon Rx data path and put a breakpoint in RxTask. Step through to verify that the priority is set correctly and packets are being copied properly. If interrupt is being asserted correctly but packet length is zero it indicates some data corruption in the receive queues or firmware behaving incorrectly, this scenario should not occur.
  5. Check if NDK is receiving the frames : If driver is receiving the frames and user cannot see frames in socket then it indicates issues with TCP/IP stack. Refer to NDK User’s guide on correct usage of sockets. The example socket application provided in the developer guide here is known to work though. In addition to this check if NDK buffers have been allocated correctly. If you are using your own TCP/IP stack refer to the Porting Guide and double check.
  6. Check if Storm prevention is enabled : This is one of the most common reasons why throughput may get lowered or if the threshold is set incorrectly packets may not reach Host at all. Check if storm prevention module is enabled by checking the variable suppressionEnabled for both ports. Refer to this for more details. Additionally one should check the statistics to see if the PRU statistics stormPrevCounter is getting incremented.
  7. Check Interface MAC : The firmware compares the interface MAC written to the PRU memory by the Host against the incoming packets destination MAC to verify if the packet must be forwarded to Host or cut-through. Please refer to the memory map and check if the MAC value is what you are expecting it to be.
  8. Queue Overflow : If too many packets are received on a single queue without Host emptying them out then overflow may occur, packets will be lost in such a scenario. This is somewhat related to throughput issues but may occur independently as well.
  9. Check throughput : This is applicable in case everything else appears to be correct but the number of packets reaching the Host is not 100% of the transmitted value. This can happen because of two reasons. 1. Data rate is too fast and interrupt pacing is disabled. 2. Processing on Host is too slow and driver cannot cope with the rate at which firmware is putting data in the queue. In such a scenario first turn on Interrupt pacing to find if it solves the issue (interrupt pacing has it’s own limitations, refer to this to know more about it), if issue is still not resolved then try to find the throughput by comparing the number of packets received on the Host vs that in the firmware.

More on Throughput : If throughput is low then try to find out how the Rx processing on Host can be sped up or if any other high priority task is blocking the execution of RxTask. The EMAC and switch are tested during release to cope with 100% throughput at line rate (960 IPG and 64 byte size packet) so any drop in throughput can only be caused by additional loading on the CPU. Use UIA which comes SYSBIOS for this purpose. Usage given here

6.9.3.2.5. Checking if Transmit is working

Because of it’s nature Tx is much more reliable and there are far fewer issues related to it when compared to Rx. Transmit issues can be classified into two types. See Tx data path for more information.

  1. Cut-through issues : Packets received on one port and meant to go out of the opposite port. (Not applicable to EMAC)
  2. Transmit from Host : Packets sent out from the Host on any one port.

As a first step please check the statistics on firmware as well as Host to see if any packets have been sent out. Try to trace where the issue is by comparing transmit statistics for Host and firmware.

The probable causes for transmit not working are listed below. This can also be used as a checklist for debugging.

  1. Link down : The link event is mapped to an ISR ICSS_EmacLinkISR which in turn calls another API ICSS_EmacUpdatePhyStatus to update the link status in firmware. If this is not done correctly then it’s possible that firmware will read the event as link down even though physically the link is up. Please check the link status to make sure that this is not the case. The Tx API checks for link and will not transmit if the link is down so this issue is more relevant to cut-through/store-forward. More on Link status here.
  2. Incorrect speed : The link ISR also checks for speed and duplexity values. The values are written to in the same ISR ICSS_EmacUpdatePhyStatus, if the speed is read incorrectly then it’s possible that firmware will not send out packets or may send out garbage. In such a scenario firmware statistics will count the packets as successful transmit but Tx might not actually happen. The quickest way to debug this issue is to read the ICSS memory directly in CCS memory window. Interface speed is written directly in memory at the offset mentioned in memory map, please verify the value (as mentioned in memory map) and compare with the actual interface speed.
  3. Incorrect pinmux for Collision/Carrier Sense : This is applicable in case of developers using their custom boards, it’s important that the collision and carrier sense signals be wired correctly (see ICEv2 layout) because the transmit code relies on these two signals to implement half duplex functionality and wrong values may result in transmit problems. If there is an issue with pinmuxing these two pins it’s recommended that half duplex functionality be disabled. Half Duplex functionality is controlled by the variable halfDuplexEnable
  4. Queue contention issues : Looking at the QoS scheme it’s possible that there is a contention for the transmit queue when both Host and the opposite port are trying to transmit on the same port. In such cases if there are too many packets vying for the contention queue they will be dropped. Such conditions are rare.
  5. Queue overflow : As the name suggests if too many packets are sent out on a single queue then overflow can happen and packets may get lost.
  6. NDK transmit : Issues with NDK buffers may cause issues with Tx, in such cases put a breakpoint in ICSS_EmacTxPacket to see if NDK is calling it.
6.9.3.2.6. Check Statistics

Statistics form the core of debugging so this section is very important. A brief introduction to statistics has been provided previously in the statistics section of developer guide. This part explains how to use it for the purpose of debugging.

As previously explained, statistics can be divided into two groups

  • On Firmware
  • Host based

Host statistics are a subset of Firmware based statistics except some specialized statistics like rxUnknownProtocol and linkBreak. This property can be used to find out how many packets are being received in the firmware and how many are reaching Host.

6.9.3.2.6.1. Getting the values

Statistics are accessible in three ways

  • IOCTL calls : IOCTL calls (including an example) have been previously explained here in developer guide.
  • Reading directly in memory window : (This applies only to PRU based statistics). Use the statistics memory map to find out the offset and look at the memory directly. Information on how to access the ICSS memory is provided here.
  • In CCS watch window : When using CCS the statistics can be read directly through the ICSS EMAC handle. Host statistics are available through hostStat while PRU statistics are available through pruStat. An example code snippet from TxPacketEnqueue API shows host statistics being accessed.
hostStatistics_t* hostStatPtr;
hostStatPtr = (hostStatistics_t*)((((ICSSEMAC_Object*)icssEmacHandle->object)->hostStat));
/*Access port specific statistics by incrementing the pointer*/
hostStatPtr += (portNumber - 1);
ICSS_EmacUpdateTxStats(macAddr,(unsigned int)lengthOfPacket, hostStatPtr);

NOTE : Since they are void members they need to be typecast to access the members in CCS watch window.

6.9.3.2.6.2. Example Usage

Described below are some scenarios which involve multiple statistics, this will help the developer understand how to use statistics.

Example 1: For example assume that 100k multicast packets of size 64 bytes each are sent to Port 1 of switch (EtherNet/IP adapter example) and storm prevention is enabled such that 10k out of those 100k packets are dropped, out of those 990k, 10k packets have CRC error so the total number of packets reaching Host is only 980k but 990k packets get cut-through (multicast packets are cut-through except some protocol specific packets) because CRC is not verified for cut-through frames. For this example the statistics will look like this (only relevant fields have been populated)

Member Host Stats Port 0 Stats Port 1 Stats
rxMcast 980,000 Example Example
txMcast 0 Example Example
rxCRCFrames NA 10,000 0
stormPrevCounter NA 10,000 0

6.9.3.3. Accessing Memory

6.9.3.3.1. ICSS Shared RAM

This section explains how to access ICSS memory. The icss_emacSwitch.h file contains the offset information.

The DRAM base addresses for Port 1 and Port 2 can be obtained by adding emacHandle1 to Expressions tab in CCS and typecasting it to ICSSEMAC_HwAttrs.

For AM335x, the addresses are:

../_images/Dramaddr.png

Example: For example, if storm prevention counter location needs to be accessed for Port 1 of ICEv2 EVM, the following steps give the value of the location to be entered in the Memory Browser of CCS:
#define STORM_PREVENTION_OFFSET      STATISTICS_OFFSET + STAT_SIZE

where, STATISTICS_OFFSET is 0x1f00 and STAT_SIZE is RX_1024_MAX_BYTE_FRAME_OFFSET + 4, RX_1024_MAX_BYTE_FRAME_OFFSET is defined as 0x88. This gives 0x1f00 + 0x88 + 4 = 0x1f8c

Hence enter 0x4a301f8c in the Memory Browser and check the content. If the value is 01, storm prevention functionality is enabled and if it is 00, it is disabled.

../_images/Stormprev.png

Similarly, the value would be 0x4a302000 + 0x1f8c (DRAM base address for Port 2 + Storm Prevention Offset) = 0x4a303f8c for Port 2 of ICEv2.

For AM437x, the DRAM base addresses are as follows:

../_images/Dramaddram4.png

6.9.3.4. System Debug

6.9.3.4.1. SYS/BIOS
6.9.3.4.1.1. Using ROV to Debug RTOS

To view ROV tab, goto Tools -> RTOS Object View (ROV) and halt the debug session.

../_images/Rov.png

6.9.3.4.1.2. Checking the system performance using UIA

The UIA (Unified Instrumentation Architecture) is a target-side package that provides instrumentation services which can be downloaded from [1]. System Analyzer is a suite of host-side tools that use data captured from software instrumentation, hardware instrumentation, and CPU trace to provide visibility into the real-time performance of the target application, which includes the menu commands in Tools > RTOS Analyzer menu of CCS.

The following code needs to be added to the configuration file to enable performance tests on AM335x/AM437x using UIA 2.x version:

var LoggingSetup = xdc.useModule('ti.uia.sysbios.LoggingSetup');
var SysStd = xdc.useModule('xdc.runtime.SysStd');
System.SupportProxy = SysStd;
/* Enable CPU Load logging */
LoggingSetup.loadLogging = true;
/*
 *  Enable Task, Swi, and Hwi Load logging. This allows the Idle Task
 *  usage to make more sense. Otherwise Hwi and Swi load is factored into
 *  each task's usage.
 */
LoggingSetup.loadTaskLogging = true;
LoggingSetup.loadSwiLogging = true;
LoggingSetup.loadHwiLogging = true;
LoggingSetup.sysbiosHwiLogging = true;
LoggingSetup.sysbiosSwiLogging = true;
LoggingSetup.sysbiosLoggerSize = 65536;
Main.common$.diags_ENTRY = Diags.ALWAYS_ON;
Main.common$.diags_EXIT = Diags.ALWAYS_ON;
LoggingSetup.disableMulticoreEventCorrelation = true;

For new log records, the ARM should be paused. The CPU load graph gives the loading percentage which can be used to determine the additional task needed to load CPU to a specific level to perform NDK tests at different loads.


6.9.3.4.1.3. Using SYS/BIOS Timer to measure performance
6.9.3.4.2. NDK
6.9.3.4.2.1. Performing NDK tests

The steps to be followed in order to enable NDK Performance Tests are:

1. Add this code snippet to the respective configuration files (am335x_app.cfg or am437x_app.cfg)

Global.networkOpenHook = "&netOpenHook";
Global.networkCloseHook = "&netCloseHook";

2. Ensure that nethooks.c file is present in the application folder. (If not, copy it from \ti_internalexamplesethernet_switchTcp)

  1. Build and load the application.

4. In windows command prompt, navigate to the location where send.exe resides in the test PC (e.g., C:tindk_2_24_02_31packagestindkwinapps).

  1. Enter this command: send.exe %DUT_IP_ADDRESS% 100

where,

DUT_IP_ADDRESS=192.168.2.3 for Port 1 and 192.168.1.3 for Port 2 in case of EMAC application

100 is the console print interval, i.e., a console print appears for every 100 packets transmitted

6. Similarly, recv.exe, echoc.exe and testudp.exe applications are run to test performance.


6.9.3.4.2.2. Measuring network performance

The network performance can be measured from the console output upon running the above tests. Consider the log when send.exe application is run for a few minutes till it stabilizes as below:

../_images/Ndksend.png

Here, 8192 bytes are being sent at 12800000 bytes/s. As NDK performance is measured at MBPS (Megabits per second), conversion is:

1 byte = 7.6294e-6 megabits

which gives (12800000*8/1024)/1024 = 97.65 MBPS

Note: The above procedure is applicable for send.exe, recv.exe and echoc.exe tests. The testudp.exe application tests UDP packet payloads from 1 to 1472 bytes and test loop should pass.


6.9.3.4.2.3. Checking NDK Buffers

6.9.3.5. Frequently Encountered Issues

6.9.3.5.1. Build Issues
6.9.3.5.1.1. Tools compatibility

One of the frequent issues faced during build are issues of tools compatibility. The SDK build is dependent on NDK, SysBIOS and XDC Tools. While we try to maintain backward compatibility it’s not always possible to do so, hence it’s recommended that the correct versions of the tools are downloaded and used. The compatible versions are listed in the user guide (sample) of every SDK release.

6.9.3.5.1.2. System Variables

The variable IA_SDK_HOME must point to (place where SDK is installed)/public/sdk, most often than not this is the main reason for build issues, especially when multiple SDK’s are installed. This variable is used everywhere during the build process to select include files, libraries, tools etc.

6.9.3.5.1.3. Migration from 1.1 to 2.1 Industrial SDK

There is a possibility of build issue while migrating from 1.1 to 2.1 Industrial SDK. The “Debug” folder needs to be removed from the project as separate build configurations are available for AM335x and AM437x EVMs in 2.1 SDK.

6.10. PRUSS

6.10.1. Overview

6.10.1.1. Introduction

The PRUSS (Programmable Real-Time Unit Subsystem) provides a well-defined API layer which allows applications to use the PRUSS low level driver to control  sub system.

Firmware

The PRUSS (Programmable Real-Time Unit Subsystem) is firmware programmable and can take on various personalities. Examples include an ethernet MAC, ethernet Switch, Industrial protocol switch. For a good example, please refer to Simple Open Real Time Ethernet Protocol (SORTE)

Driver Features

  • PRU control features i.e enable/disable/reset a PRU
  • Helper functions i.e. load and execute firmware in PRU
  • Memory mapping of PRU/L3/External memories
  • PRU and Host event management (i.e. map sys_evt/channel/hosts in PRU INTC generate interrupts, wait for occurrence of an event, and acknowledge interrupts
  • Interrupt management for A15/C66x CPU targets

6.10.2. User Interface

6.10.2.1. Driver Configuration

Board Specific Configuration

All the board specific configurations like enabling the clock and pin-mux of UART/GPIO/PRUSS ICSS pins should be performed before calling any of the driver APIs.


PRUSS Configuration Structure

The pruicss_device.c file contains the declaration of the PRUICSS config structure. This structure must be provided to the driver at the time when PRUICSS_create() API is called to creat the PRUICSS_Handle. This handle is subsequently required to make any PRUSS LLD API call.

6.10.2.2. APIs

Reference API header file:

#include <ti/drv/pruss/pruicss.h>

API Call Flow

Below sequence indicates calling sequence of PRUSS driver APIs for a use case of sending INTC event to the PRU. Refer example code within module for additional details

...
/* Initialize Board */
Board_init(boardCfg);

/* Creates handle for PRUICSS instance */
handle = PRUICSS_create(pruss_config,instance);

/* Disable PRUICSS instance */
PRUICSS_pruDisable(handle,instance );

/* Register an Interrupt Handler for an event */
PRUICSS_registerIrqHandler(handle,pruEvtoutNum,intrNum,eventNum,waitEnable,irqHandler);

/* Sets the buffer pointer for PRU */
PRUICSS_setPRUBuffer(..);

/* API to do Interrupt-Channel-host mapping */
PRUICSS_pruIntcInit(handle,&pruss_intc_initdata);

/* Execute program on PRU */
PRUICSS_pruExecProgram(handle,0);

 /* Enable PRU */
PRUICSS_pruEnable(handle,0);

/* Generates INTC event */
PRUICSS_pruSendEvent(handle,ARM_PRU0_EVENT);

6.10.3. Application

6.10.3.1. Examples

Name
Description
Expected Results
PRUSS_TestApplication
Test application is designed to ping pong an event between CPU target(A15/C66x) and PRU for a fixed count.Application is to test PRU’s load, control and Interrupt controller functionalities.
Following prints expected on console based on pass/fail criteria:

Pass criteria:
Prints related to sending and receiving  event from PRU will be printed on  console. Test program at the end expected to output: “All tests have passed”

6.10.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\pruss\docs\doxygen\html\inde x.html
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \drv\pruss\docs\ReleaseNotes_PRUS S_LLD.pdf

6.11. FATFS

6.11.1. Overview

6.11.1.1. Introduction

FATFS module provides an interface to configure a driver for FAT file system compatible device that connects via MMCSD, USB, etc. It configures FATFS for disk operations driver disk Initialize, disk read, disk write

6.11.2. User Interface

6.11.2.1. Driver Configuration

Board Specific Configuration

All board specific configurations eg:enabling clock and pin-mux for UART pins are required before calling any driver APIs.By default Board_Init() API supports all initialization sequence for TI supported EVMs. In addition it initializes UART instance for Console/STDIO.Refer Processor SDK RTOS Board Support for additional details.Once board specific configuration is complete FATFS_init() API can be called to initialize FATFS for the driver.

FATFS Configuration Structure

Application is expected to perform driver specific configuration for FATFS_config structure. The structure supports initialization of multiple drivers for FATFS, i.e. both MMCSD and USB can be configured to use FATFS file system by configuring each driver to different drive instance. This structure must be provided to the FATFS driver. It must be initialized before the FATFS_init() function is called and cannot be changed subsequently. For details about individual fields of this structure, see the Doxygen help:PDK_INSTALL_DIR\packages\ti\fs\fatfs\docs\doxygen\html\index.html.

6.11.2.2. APIs

In order to use the FATFS module APIs, the FATFS.h and ff.h header file should be included in an application as follows:

#include <ti/fs/fatfs/FATFS.h>
#include <ti/fs/fatfs/ff.h>

API Call Flow

Below sequence indicates the calling sequence of FATFS driver APIs:

FATFS_Handle FATFS;
FATFS_Params FATFSParams;
FATFS_Params_init(&FATFSParams);
FATFS = FATFS_open(peripheralNum, &FATFSParams);

At this point application can invoke additional FAT File system API eg: f_open(), f_write(), f_read() etc to perform file operations on device

6.11.3. Application

6.11.3.1. Examples

Name
Description
Expected Results
FATFS Example application
Example will initialize card and checks for valid FAT partition. When a valid FAT partition is detected console interface for command execution is provided. Supported console commands include ls (to list files of directory), cd (change directory), pwd (present working directory) and cat (text file read operation).
When a card is detected with valid FAT partition console interface output will indicate “0:> “

6.11.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \fs\fatfs\docs\doxygen\html\index .html
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \fs\fatfs\docs\ReleaseNotes_FATFS _LLD.pdf

6.12. MMCSD

6.12.1. Overview

6.12.1.1. Introduction

MMCSD module provides an interface between CPU and any MMCSD-bus-compatible device that connects via MMCSD serial bus. External components attached to MMCSD bus can serially transmit/receive data to/from the CPU device through two-wire interface

Key Features

Type of transfers
  •  Read
  •  Write
  •  Write followed by read
Operating modes
  •  Blocking(interrupt or Non interrupt)
  •  Callback mode(interrupt)
Supports only master mode. Slave mode is not supported

6.12.2. User Interface

6.12.2.1. Driver Configuration

Board Specific Configuration

All board specific configurations eg:enabling clock and pin-mux for UART pins are required before calling any driver APIs.By default Board_Init() API supports all initialization sequence for TI supported EVMs. In addition it initializes UART instance for Console/STDIO.Refer Processor SDK RTOS Board Support for additional details.Once board specific configuration is complete MMCSD_init() API can be called to initialize driver.

MMCSD Configuration Structure

The MMCSD_soc.c file binds driver with hardware attributes on the board through MMCSD_config structure. This structure must be initialized before the MMCSD_init() function is called and cannot be changed afterwards. For details about the individual fields of this structure, see the Doxygen help by opening \docs\doxygen\html\index.html

6.12.2.2. APIs

Reference for API header file with documentation

#include <ti/drv/mmcsd/MMCSD.h>

API Call Flow

The below sequence indicates the calling sequence of MMCSD driver APIs for a use case of write transaction in blocking mode:

MMCSD_Handle MMCSD;
UInt peripheralNum = 0; /* Such as MMCSD0 */
MMCSD_Params MMCSDParams;
...
MMCSD_Params_init(&MMCSDParams);
MMCSD = MMCSD_open(peripheralNum, &MMCSDParams);<br>if (MMCSD == NULL) {<br> /* Error opening MMCSD */
...
readOK = MMCSD_read(MMCSD, rxBuffer , startBlock, numBlock); /* Perform MMCSD read */
if (!transferOK) { /* MMCSD transaction failed */}

writeOK = MMCSD_write(MMCSD, TxBuffer , startBlock, numBlock); /* Perform MMCSD write */
if (!writeOK) { /* MMCSD transaction failed */}

eMMC Usage

MMCSD driver supports eMMC device. Application need to configure the eMMC device for an instance of peripheral. It is also recommended to configure the operating bus width of eMMC device.

mmcsdInitCfg[MMCSD_INSTANCE].cardType = MMCSD_CARD_EMMC;
mmcsdInitCfg[MMCSD_INSTANCE].supportedBusWidth = MMCSD_BUS_WIDTH_8BIT;
MMCSD_init();

EDMA Usage

MMCSD driver supports EDMA operations to transfer data between memory and MMCSD peripheral.

Driver uses separate source files for these operations.Refer source MMCSD_soc.c for DMA MMCSD SOC configuration. Application need to create EDMA handle and update the configuration before MMCSD_init() API.

mmcsdInitCfg[MMCSD_INSTANCE].edmaHandle = MMCSDApp_edmaInit();/* Refer Example/Test */
MMCSD_init();

Refer “MMCSD_[Usecase]_[Board/SoC]_DMA_[cpu][Example/Test]project” for additional reference. Refer SDK Release Note for supported EVMs.

UHS Mode Usage

The MMCSD driver supports UHS-I cards. Feature is available for AM57x SOC and is dependent on board or platform support for run-time switching from 3.0V to 1.8V. Feature is validated on AM572x GP EVM 3.0

6.12.3. Application

6.12.3.1. Examples

6.12.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\mmcsd\docs\doxygen\html\inde x.html
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \drv\mmcsd\docs\ReleaseNotes_MMCS D_LLD.pdf

6.13. QMSS

6.13.1. Overview

6.13.1.1. Introduction

The Queue Manager Sub System (QMSS) low level driver provides the interface to Queue Manager Subsystem hardware which is part of the Multicore Navigator functional unit for a keystone device. QMSS provides hardware assisted queue system and implements fundamental operations such as en-queue and de-queue, descriptor management, accumulator functionality and configuration of infrastructure DMA mode. The LLD provides APIs to get full entitlement of supported hardware functionality.

The LLD also includes accumulation and QoS (Quality of Service) firmware. QoS enables restriction of data rates in bytes per second or packets per second, weighted round robin queue selection, and selective descriptor dropping for oversubscribed queues. Accumulation The APIs are provided through the LLD. The API documentation for both QoS and Accumulator is available in the API Reference manual below. The capabilities of the QoS firmware are documented in their design documents. The capabilities of the accumulator are documented in the Hardware Peripheral User Guide.

Modes of Operation

QMSS library (ti.drv.qm) supports below modes

Joint Mode: In this mode, only linkingRAM0Base, linkingRAM0Size, and linkingRAM1Base are used to configure all QM groups simultaneously. For all existing devices (K2H, K2K) this is only mode that should be used. For the rest of the devices such as K2L, K2E, 6678 and 6657, this is the only mode available.

Split Mode: This mode shouldn’t be used as it doesn’t support all peripherals on the device.

6.13.2. User Interface

6.13.2.1. Driver Configuration

The driver configures the QMSSSS subsystem using Qmss_GlobalConfigGroupRegs(system configuration) structure. The default global configuration per device is present under qmss_device.c file provided per device.

For details about individual fields of this structure, see the Doxygen help by opening PDK_INSTALL_DIRQMSSckagestidrvQMSSdocsdoxygenhtmlindex.html.

6.13.2.2. APIs

API header for application:

#include <ti/drv/QMSS/QMSS_drv.h>

Please see the doxygen in “API Reference Manual” below for details.


6.13.3. Application

6.13.3.1. Examples

Name
Description
Expected Results
QMSS_Example application
Example demonstrating infra DMA, interrupt test use case. Reference example for developers
User observes the output printed over the CCS console
QMSS_UnitTestApplicat ion
Unit Test application to test all APIs
User observes the output printed over the CCS console

Sample Example Output

This came from K2K multicore example:

**************************************************
************ QMSS Multicore Example **************
**************************************************
**************************************************
************ QMSS Multicore Example **************
**************************************************
**************************************************
**************************************************
************ QMSS Multicore Example **************
************ QMSS Multicore Example **************
**************************************************
**************************************************
Core 1 : Starting BIOS...
Core 2 : Starting BIOS...
Core 3 : Starting BIOS...
Core 0 : Starting BIOS...
Core 0 : Created RM packet heap
Core 0 : Created IPC MessageQ heap
Core 0 : Created receive Q for Client1
Core 1 : Opened RM packet heap
Core 2 : Opened RM packet heap
Core 3 : Opened RM packet heap
Core 1 : Opened IPC MessageQ heap
Core 2 : Opened IPC MessageQ heap
Core 3 : Opened IPC MessageQ heap
Core 1 : Created receive Q for Server
Core 2 : Created receive Q for Server
Core 3 : Created receive Q for Server
Core 1 : Opened Server's receive Q
Core 1 : Waiting for QMSS to be initialized...

Core 0 : Opened Client1's receive Q for Server
Core 0 : Created receive Q for Client2
Core 0 : Opened Client2's receive Q for Server
Core 0 : Created receive Q for Client3
Core 2 : Opened Server's receive Q
Core 2 : Waiting for QMSS to be initialized...

Core 0 : Opened Client3's receive Q for Server

-----------------------Initializing---------------------------
Core 0 : L1D cache size 4. L2 cache size 0.
Core 0 : Memory region 0 inserted
Core 0 : Memory region 1 inserted
Core 0 : Tx Completion Queue Number     : 897 opened
Core 0 : Number of Tx descriptors requested : 32. Number of descriptors allocated : 32
Core 0 : Number of Rx descriptors requested : 32. Number of descriptors allocated : 32
Core 0 : Number of Sync free descriptors requested : 32. Number of descriptors allocated : 32
Core 0 : Sync Queue Number              : 9025 opened
Core 0 : Sync Cfg Queue Number          : 9026 opened
Core 0 : Sync Free Queue Number         : 898 opened
Core 0 : Receive Free Queue Number      : 736 opened
Core 0 : Transmit Free Queue Number     : 8928 opened
Core 0 : System initialization completed: 8928
Core 0 : Publishing RM nameserver names for shared queues

--------------------Queue status CORE 0----------------------
                    After Initialization

Tx Free Queue 8928 Entry Count            : 32
Rx Free Queue 736 Entry Count            : 32
Tx completion Queue 897 Entry Count     : 0
Sync Queue 9025 Entry Count              : 0
Sync free Queue 898 Entry Count         : 32
Sync Cfg Queue 9026 Entry Count          : 0
-------------------------------------------------------------

Core 0 : Registering High Priority interrupt channel : 0 eventId : 48 queue Number : 704


Core 3 : Opened Server's receive Q
Core 1 : QMSS initialization done.
Core 2 : QMSS initialization done.
Core 3 : Waiting for QMSS to be initialized...




Core 3 : QMSS initialization done.

Core 1 : Rx Free Queue Number       : 736 opened
Core 2 : Rx Free Queue Number       : 736 opened
Core 3 : Rx Free Queue Number       : 736 opened
Core 1 : Tx Free Queue Number       : 8928 opened
Core 2 : Tx Free Queue Number       : 8928 opened
Core 3 : Tx Free Queue Number       : 8928 opened
Core 1 : Tx Completion Queue Number : 897 opened
Core 2 : Tx Completion Queue Number : 897 opened
Core 3 : Tx Completion Queue Number : 897 opened
Core 1 : Sync Queue Number          : 9025 opened
Core 2 : Sync Queue Number          : 9025 opened
Core 3 : Sync Queue Number          : 9025 opened
Core 1 : Sync Free Queue Number     : 898 opened
Core 2 : Sync Free Queue Number     : 898 opened
Core 3 : Sync Free Queue Number     : 898 opened
Core 1 : Sync Cfg Queue Number      : 9026 opened
Core 2 : Sync Cfg Queue Number      : 9026 opened
Core 3 : Sync Cfg Queue Number      : 9026 opened
Core 1 : Registering High Priority interrupt channel : 1 eventId : 48 queue Number : 705
Core 2 : Registering High Priority interrupt channel : 2 eventId : 48 queue Number : 706
Core 3 : Registering High Priority interrupt channel : 3 eventId : 48 queue Number : 707
Core 1 : Waiting for sync signal
Core 2 : Waiting for sync signal
Core 3 : Waiting for sync signal
Core 0 : Opened Tx channel      : 0
Core 0 : Opened Rx channel      : 0
Core 0 : Transmit Queue Number  : 800
Core 0 : Receive Queue Number   : 704
Core 0 : Opened Rx flow         : 0
Core 0 : High priority accumulator programmed for channel : 0 queue : 704

Core 0 : Transmitting 8 packets..........

*************************************************************
Core 0 : Opened Tx channel      : 0
Core 0 : Opened Rx channel      : 0
Core 0 : Transmit Queue Number  : 800
Core 0 : Receive Queue Number   : 705
Core 0 : Opened Rx flow         : 0
Core 0 : High priority accumulator programmed for channel : 1 queue : 705

Core 0 : Transmitting 8 packets..........

*************************************************************
Core 0 : Opened Tx channel      : 0
Core 0 : Opened Rx channel      : 0
Core 0 : Transmit Queue Number  : 800
Core 0 : Receive Queue Number   : 706
Core 0 : Opened Rx flow         : 0
Core 0 : High priority accumulator programmed for channel : 2 queue : 706

Core 0 : Transmitting 8 packets..........

*************************************************************
Core 0 : Opened Tx channel      : 0
Core 0 : Opened Rx channel      : 0
Core 0 : Transmit Queue Number  : 800
Core 0 : Receive Queue Number   : 707
Core 0 : Opened Rx flow         : 0
Core 0 : High priority accumulator programmed for channel : 3 queue : 707

Core 0 : Transmitting 8 packets..........

*************************************************************
Core 0 : Waiting for sync signal
Core 0 : Got sync signal
*************************************************************


--------------------Queue status CORE 0----------------------
                    After packet processing

Tx Free Queue 8928 Entry Count            : 0
Rx Free Queue 736 Entry Count            : 32
Tx completion Queue 897 Entry Count     : 32
Sync Queue 9025 Entry Count              : 4
Sync free Queue 898 Entry Count         : 27
Sync Cfg Queue 9026 Entry Count          : 1
-------------------------------------------------------------

Core 0 : Waiting for other cores to ack sync signal
Core 1 : Got sync signal
Core 2 : Got sync signal
Core 3 : Got sync signal
*************************************************************
*************************************************************
*************************************************************



Core 0 : acks found

--------------------Deinitializing---------------------------

--------------------Queue status CORE 0----------------------
                    Before exit

Tx Free Queue 8928 Entry Count            : 0
Rx Free Queue 736 Entry Count            : 32
Tx completion Queue 897 Entry Count     : 32
Sync Queue 9025 Entry Count              : 0
Sync free Queue 898 Entry Count         : 28
Sync Cfg Queue 9026 Entry Count          : 4
-------------------------------------------------------------

Core 0 : Receive free queue closed successfully. Ref count : 0
Core 0 : Transmit completion queue closed successfully. Ref count : 3
Core 0 : Transmit free queue closed successfully. Ref count : 3
Core 0 : Sync queue closed successfully. Ref count : 3
Core 0 : Sync free queue closed successfully. Ref count : 3
Core 0 : Sync queue closed successfully. Ref count : 3
Core 0 : CPPI CPDMA closed successfully
Core 0 : CPPI exit successful
Core 0: Cleaning regions
Core 0: exit QMSS
Core 1 : Receive free queue closed successfully. Ref count : 3
Core 2 : Receive free queue closed successfully. Ref count : 2
Core 3 : Receive free queue closed successfully. Ref count : 1
Core 1 : Transmit completion queue closed successfully. Ref count : 2
Core 2 : Transmit completion queue closed successfully. Ref count : 1
Core 3 : Transmit completion queue closed successfully. Ref count : 0
Core 1 : Transmit free queue closed successfully. Ref count : 2
Core 2 : Transmit free queue closed successfully. Ref count : 1
Core 3 : Transmit free queue closed successfully. Ref count : 0
Core 1 : Sync queue closed successfully. Ref count : 2
Core 2 : Sync queue closed successfully. Ref count : 1
Core 3 : Sync queue closed successfully. Ref count : 0
Core 1 : Sync free queue closed successfully. Ref count : 2
Core 2 : Sync free queue closed successfully. Ref count : 1
Core 3 : Sync free queue closed successfully. Ref count : 0
Core 1 : Sync queue closed successfully. Ref count : 2
Core 2 : Sync queue closed successfully. Ref count : 1
Core 3 : Sync queue closed successfully. Ref count : 0
*******************************************************
*******************************************************
*******************************************************
******** QMSS Multicore (1) Example Done (PASS) *******
******** QMSS Multicore (2) Example Done (PASS) *******
******** QMSS Multicore (3) Example Done (PASS) *******
*******************************************************
*******************************************************
*******************************************************
Core 0 : Deleting RM nameserver names for shared queues
Instance name: RM_Server
Handle: 0x00854578
Type:   Server

Resource Status:

Core 0 : All resources freed successfully
*******************************************************
******** QMSS Multicore (0) Example Done (PASS) *******
*******************************************************

6.13.4. Debug FAQ

  1. Double Push - Some queue elements lost.
    1. Pushing the same pointer twice is illegal. In hardware it does something similar to double linking the same object into two places of a software linked list. It corrupts the list, such that some items will be orphaned/lost.
  2. NULL Push - Entire queue lost
    1. Pushing NULL (0) clears the entire queue. This is intentionally done by Qmss_QueueEmpty(). However the various Qmss_QueuePush functions don’t check for NULL (to save cycles). Don’t push NULL (for example received when Qmss_QueuePop finds an empty queue).
  3. Hint Bits (4 low LSBs of desc pointer)
    1. These are used to tell DMAs such as CPPI the size of the descriptor. Thus, when receiving descriptors from hardware, you must use QMSS_DESC_PTR() to discard them, else unaligned memory accesses that corrupt descriptors will be generated by software.
  4. General lost descriptors
    1. Its not a bad idea to have code that can inventory all your descriptors as part of destructive debug. Iterate over all queues, and pop all descriptors. Set a bit in a large bitmap for each descriptor found. Bits that remain 0 indicate “lost” descriptors which could have happened due to double push or null push or software bugs that simply lost them. By examining the contents of descriptor(s) and buffer(s), can often determine who last used them therefore what part of code lost them.
    2. Its also good to have nondestructive debug code that can call Qmss_getQueueByteCount() and Qmss_getQueueEntryCount() for each queue. This should be able to find all but a few (~4) descriptors per hardware DMA that are in flight. If large amounts of descriptors are missing, it means there is a bug. For this debug/monitor purpose, its OK to make own Qmss_QueueHandle by casting the queue number (eg (Qmss_QueueHandle)queueNum) since its undesirable to generate accounting/management for purpose of nondestructive debug.

6.13.5. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)/packages/ti /drv/QMSS/docs/doxygen/html/index .html
Release Notes $(TI_PDK_INSTALL_DIR)/packages/ti /drv/QMSS/docs/ReleaseNotes_QMSS_ LLD.pdf
QoS (Weighted Round Robin and SP QoS tree) $(TI_PDK_INSTALL_DIR)/packages/ti /drv/QMSS/docs/firmware/qos_sched ,qos_sched_drop_sched,qos_sched_w ide.pdf
QoS (Leaky bucket and SRIO TX Scheduler) $(TI_PDK_INSTALL_DIR)/packages/ti /drv/QMSS/docs/firmware/qos.pdf
Hardware Userguide/TRM UG TRM PDF
CPPI LLD (Navigator/QMSS DMA component) CPPI LLD

6.14. CPPI

6.14.1. Overview

6.14.1.1. Introduction

CPPI offers developers a common way of handling different protocol interfaces that may require multiple priorities and multiple channels on a single port. CPPI defines the register set, data structures, interrupts and buffer handling for all peripherals, regardless of protocol.

CPPI is based on a buffer scatter/gather scheme, in which individual packets are broken up and then stored into small buffers, from which they are retrieved and reassembled (as opposed to using buffers that are located contiguously in memory). When protocol translation is required, a packet header can be appended in a small buffer, saving the CPU from having to rewrite the entire packet and header by performing a copy from one large buffer to another. The considerable savings in CPU cycles that result make buffer scatter/gathering the most efficient scheme for bridging and routing.

The LLD provides resource management for descriptors, receive/transmit channels and receive flows.

6.14.2. User Interface

6.14.2.1. Driver Configuration

The driver configures the CPPI subsystem using cppiGblCfgParams(system configuration) structure. The default global configuration per device is present under cppi_device.c file provided per device.

For details about individual fields of this structure, see the Doxygen help by opening PDK_INSTALL_DIRCPPIckagestidrvCPPIdocsdoxygenhtmlindex.html.

6.14.2.2. APIs

API reference for application:

#include <ti/drv/CPPI/CPPI_drv.h>

6.14.3. Application

6.14.3.1. Examples

Name
Description
Expected Results
CPPI_Example application
Example demonstrating sample test use case. Reference example for developers
User observes the output printed over the CCS console
CPPI_UnitTestApplicat ion
Unit Test application to test all APIs
User observes the output printed over the CCS console

Sample Example output

This came from k2k example:

**************************************************
*************** CPPI LLD usage example ***********
**************************************************
**************************************************
*************** CPPI LLD usage example ***********
**************************************************
**************************************************
**************************************************
*************** CPPI LLD usage example ***********
*************** CPPI LLD usage example ***********
**************************************************
**************************************************
*******Test running on Core 1 *******************
*******Test running on Core 0 *******************
*******Test running on Core 2 *******************
*******Test running on Core 3 *******************
Core 0 : L1D cache size 4. L2 cache size 0.
Core 2 : Starting BIOS...
Core 3 : Starting BIOS...
Core 0 : Starting BIOS...
Core 1 : Starting BIOS...
Core 0 : Created RM packet heap
Core 0 : Created IPC MessageQ heap
Core 0 : Created receive Q for Client1
Core 1 : Opened RM packet heap
Core 2 : Opened RM packet heap
Core 3 : Opened RM packet heap
Core 1 : Opened IPC MessageQ heap
Core 2 : Opened IPC MessageQ heap
Core 3 : Opened IPC MessageQ heap
Core 1 : Created receive Q for Server
Core 2 : Created receive Q for Server
Core 3 : Created receive Q for Server
Core 1 : Opened Server's receive Q
Core 1 : Waiting for QMSS to be initialized...

Core 0 : Opened Client1's receive Q for Server
Core 0 : Created receive Q for Client2
Core 0 : Opened Client2's receive Q for Server
Core 0 : Created receive Q for Client3
Core 2 : Opened Server's receive Q
Core 2 : Waiting for QMSS to be initialized...

Core 0 : Opened Client3's receive Q for Server

Core 0 : QMSS initialization done


Core 3 : Opened Server's receive Q
Core 1 : QMSS initialization done
Core 2 : QMSS initialization done
Core 3 : Waiting for QMSS to be initialized...


Core 3 : QMSS initialization done


Core 0 : QMSS CPDMA Opened
Core 1 : QMSS CPDMA Opened


Core 0 : Memory region 0 inserted
Core 0 : Number of descriptors requested : 8. Number of descriptors allocated : 8
Core 0 : Opened Rx channel : 0
Core 0 : Opened Tx channel : 0
Core 0 : Queue Number : 8192 opened
Core 0 : Queue Number : 8193 opened
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@10853b20
Receive Queue 8193 Entry Count : 1 Rx descriptor 0x@10853b20
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@10853b50
Receive Queue 8193 Entry Count : 1 Rx descriptor 0x@10853b50
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@10853b80
Receive Queue 8193 Entry Count : 1 Rx descriptor 0x@10853b80
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@10853bb0
Receive Queue 8193 Entry Count : 1 Rx descriptor 0x@10853bb0
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@10853be0
Receive Queue 8193 Entry Count : 1 Rx descriptor 0x@10853be0
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@10853c10
Receive Queue 8193 Entry Count : 1 Rx descriptor 0x@10853c10
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@10853c40
Receive Queue 8193 Entry Count : 1 Rx descriptor 0x@10853c40
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@10853c70
Receive Queue 8193 Entry Count : 1 Rx descriptor 0x@10853c70
Core 0 : Received host descriptor from Queue 897 Sucessfully
Core 0 : Tx Channel closed successfully. Ref count :0
Core 0 : Rx Channel closed successfully. Ref count :0
Core 0 : Rx queue closed successfully. Ref count :0
Core 0 : Tx queue closed successfully. Ref count :0
Core 0 : Free queue closed successfully. Ref count :0
Core 0 : Closing CPPI CPDMA Ref count : 3
Core 0 : CPPI CPDMA closed successfully
Core 1 : Memory region 1 inserted


Core 1 : Number of descriptors requested : 8. Number of descriptors allocated : 8
Core 2 : QMSS CPDMA Opened
Core 3 : QMSS CPDMA Opened
Core 1 : Opened Rx channel : 0


Core 1 : Opened Tx channel : 0
Core 2 : Memory region 2 inserted
Core 3 : Memory region 3 inserted
Core 1 : Queue Number : 0 opened
Core 2 : Number of descriptors requested : 8. Number of descriptors allocated : 8
Core 3 : Number of descriptors requested : 8. Number of descriptors allocated : 8
Core 1 : Queue Number : 1 opened
Core 2 : Opened Rx channel : 1
Core 3 : Opened Rx channel : 2
Transmit Queue 0 Entry Count : 1 Tx descriptor 0x@11853b20
Core 2 : Opened Tx channel : 1
Core 3 : Opened Tx channel : 2
Receive Queue 1 Entry Count : 1 Rx descriptor 0x@11853b20
Core 2 : Queue Number : 8192 opened
Core 3 : Queue Number : 8193 opened
Transmit Queue 0 Entry Count : 1 Tx descriptor 0x@11853b50
Core 2 : Queue Number : 8194 opened
Core 3 : Queue Number : 8195 opened
Receive Queue 1 Entry Count : 1 Rx descriptor 0x@11853b50
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@12853b20
Transmit Queue 8193 Entry Count : 1 Tx descriptor 0x@13853b20
Transmit Queue 0 Entry Count : 1 Tx descriptor 0x@11853b80
Receive Queue 8194 Entry Count : 1 Rx descriptor 0x@12853b20
Receive Queue 8195 Entry Count : 1 Rx descriptor 0x@13853b20
Receive Queue 1 Entry Count : 1 Rx descriptor 0x@11853b80
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@12853b50
Transmit Queue 8193 Entry Count : 1 Tx descriptor 0x@13853b50
Transmit Queue 0 Entry Count : 1 Tx descriptor 0x@11853bb0
Receive Queue 8194 Entry Count : 1 Rx descriptor 0x@12853b50
Receive Queue 8195 Entry Count : 1 Rx descriptor 0x@13853b50
Receive Queue 1 Entry Count : 1 Rx descriptor 0x@11853bb0
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@12853b80
Transmit Queue 8193 Entry Count : 1 Tx descriptor 0x@13853b80
Transmit Queue 0 Entry Count : 1 Tx descriptor 0x@11853be0
Receive Queue 8194 Entry Count : 1 Rx descriptor 0x@12853b80
Receive Queue 8195 Entry Count : 1 Rx descriptor 0x@13853b80
Receive Queue 1 Entry Count : 1 Rx descriptor 0x@11853be0
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@12853bb0
Transmit Queue 8193 Entry Count : 1 Tx descriptor 0x@13853bb0
Transmit Queue 0 Entry Count : 1 Tx descriptor 0x@11853c10
Receive Queue 8194 Entry Count : 1 Rx descriptor 0x@12853bb0
Receive Queue 8195 Entry Count : 1 Rx descriptor 0x@13853bb0
Receive Queue 1 Entry Count : 1 Rx descriptor 0x@11853c10
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@12853be0
Transmit Queue 8193 Entry Count : 1 Tx descriptor 0x@13853be0
Transmit Queue 0 Entry Count : 1 Tx descriptor 0x@11853c40
Receive Queue 8194 Entry Count : 1 Rx descriptor 0x@12853be0
Receive Queue 8195 Entry Count : 1 Rx descriptor 0x@13853be0
Receive Queue 1 Entry Count : 1 Rx descriptor 0x@11853c40
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@12853c10
Transmit Queue 8193 Entry Count : 1 Tx descriptor 0x@13853c10
Transmit Queue 0 Entry Count : 1 Tx descriptor 0x@11853c70
Receive Queue 8194 Entry Count : 1 Rx descriptor 0x@12853c10
Receive Queue 8195 Entry Count : 1 Rx descriptor 0x@13853c10
Receive Queue 1 Entry Count : 1 Rx descriptor 0x@11853c70
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@12853c40
Transmit Queue 8193 Entry Count : 1 Tx descriptor 0x@13853c40
Core 1 : Received host descriptor from Queue 896 Sucessfully
Receive Queue 8194 Entry Count : 1 Rx descriptor 0x@12853c40
Receive Queue 8195 Entry Count : 1 Rx descriptor 0x@13853c40
Core 1 : Tx Channel closed successfully. Ref count :0
Transmit Queue 8192 Entry Count : 1 Tx descriptor 0x@12853c70
Transmit Queue 8193 Entry Count : 1 Tx descriptor 0x@13853c70
Core 1 : Rx Channel closed successfully. Ref count :0
Receive Queue 8194 Entry Count : 1 Rx descriptor 0x@12853c70
Receive Queue 8195 Entry Count : 1 Rx descriptor 0x@13853c70
Core 1 : Rx queue closed successfully. Ref count :0
Core 2 : Received host descriptor from Queue 9026 Sucessfully
Core 3 : Received host descriptor from Queue 898 Sucessfully
Core 1 : Tx queue closed successfully. Ref count :0
Core 2 : Tx Channel closed successfully. Ref count :0
Core 3 : Tx Channel closed successfully. Ref count :0
Core 1 : Free queue closed successfully. Ref count :0
Core 2 : Rx Channel closed successfully. Ref count :0
Core 3 : Rx Channel closed successfully. Ref count :0
Core 1 : Closing CPPI CPDMA Ref count : 2
Core 2 : Rx queue closed successfully. Ref count :0
Core 3 : Rx queue closed successfully. Ref count :0
Core 1 : CPPI CPDMA closed successfully
Core 2 : Tx queue closed successfully. Ref count :0
Core 3 : Tx queue closed successfully. Ref count :0
Core 2 : Free queue closed successfully. Ref count :0
Core 3 : Free queue closed successfully. Ref count :0
Core 2 : Closing CPPI CPDMA Ref count : 1
Core 3 : CPPI CPDMA closed successfully
Core 2 : CPPI CPDMA closed successfully
Core 2 : CPPI exit successful
*******************************************************
*************** CPPI LLD usage example Done ***********
*******************************************************
Core 1 : CPPI exit successful
Core 3 : CPPI exit successful
*******************************************************
*******************************************************
*************** CPPI LLD usage example Done ***********
*************** CPPI LLD usage example Done ***********
*******************************************************
*******************************************************
Core 0 : CPPI exit successful
Core 0: exit QMSS
Instance name: RM_Server
Handle: 0x00849ee8
Type:   Server

Resource Status:

Core 0 : All resources freed successfully
*******************************************************
*************** CPPI LLD usage example Done ***********
*******************************************************

Debug FAQ

  1. CPPI Lockup
    1. CPPI can lock up if any pointer or length, including hint bits, are wrong. Use the User Guide (TRM) referenced below to verify every pointer and length in the descriptor. Also verify the hint bits (low 4 bits of each descriptor) which represents size of descriptor (not data) in 16-byte units. When using CPPI it should be at least 1 (32 bytes) if no extensions are used, or 2 (48 bytes) if some extensions are used. 0 (16 bytes) is likely to cause lock up!!
  2. See QMSS Debug FAQ for more.

6.14.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)/packages/ti /drv/CPPI/docs/doxygen/html/index .html
Release Notes $(TI_PDK_INSTALL_DIR)/packages/ti /drv/CPPI/docs/ReleaseNotes_CPPI_ LLD.pdf
Hardware Userguide/TRM UG TRM PDF
QMSS LLD (Navigator/Queueing HW component) QMSS LLD

6.15. PA

6.15.1. Overview

6.15.1.1. Introduction

The packet accelerator (PA) is one of the main components of the network coprocessor (NETCP) peripheral in KeyStone devices, including C6678, K2H/K/E/L. The PA works together with the security accelerator (SA) and the gigabit Ethernet switch subsystem to form a network processing solution. The purpose of PA in the NETCP is to perform packet processing operations such as packet header classification, checksum generation, and multi-queue routing.


6.15.1.2. Driver Configuration

The driver configures the PASS subsystem using Pa_config_t structure. This structure must be initialized before the Pa_create() function is called and cannot be changed afterwards. Also, there are bunch of system/global configurations and per entry configurations for PA. For details about individual fields of this structure and other configuration API structures, see the Doxygen help by opening PDK_INSTALL_DIR\packages\ti\drv\PA\docs\doxygen\html\index.html.

6.15.1.3. APIs

API reference for application can be found in below file:

#include <ti/drv/PA/PA.h>

6.15.2. Application

6.15.2.1. Examples

Name Description Expected Results
PA_Example application
Example demonstrating simple emac loopback use case. Reference example for developers
User observes the output printed over the CCS console
PA_UnitTestApplicatio n
Unit Test application to test all APIs
User observes the output printed over the CCS console
PA_PktCapTestApplicat ion
Packet Capture Unit Test application.
User observes the output printed over the CCS console

6.15.3. FAQ

What is the difference between internal loopback and external loopback?

  • CPSW_LOOPBACK_INTERNAL (default): The transmitted packet is loopbacked at the SGMII through SGMII internal loopback
  • CPSW_LOOPBACK_EXTERNAL: The transmitted packet should be loopbacked by an application outside of the SOC, e.g., PC, PHY.

How to test PA EMAC example with a PC?

The EVM has to be connected to PC via RJ-45 port. By default, the PA example uses the internal loopback mode, please change code: int cpswLpbkMode = CPSW_LOOPBACK_INTERNAL to CPSW_LOOPBACK_EXTERNAL.

To test the egress path (from SOC to PC):

  • Rebuilt the CCS project, load and run.
  • The PC should receive 10 identical UDP packets sending out by the PA example, the packet is defined by an array pktMatch[] in the code.

To test the ingress direction (from PC to SOC): The PC needs a tool to send out packets with controlled MAC address, IP address and UDP port matching the PA layer 2, 3 and 4 classifications, defined by the following functions:

  • Add_MACAddress(): ethInfo.dst
  • Add_IPAddress(): ipInfo.dst
  • Add_Port (): ports

How to use PA EMAC example to test other Ethernet ports than default?

The Keystone devices may have multiple Ethernet ports, connected through an internal GbE switch with a host port. There is a pre-defined symbol “NUM_PORTS” in the text file when creating the PA project. This controls how many ports used in loopback mode test. In non-loopback case, the port number may be hardcoded by gNum_Mac_Ports. This has to be changed for the test. On EVMs, those additional Ethernet ports may be accessed by various ways: Rear-Transition Module – Breakout Card (RTM-BOC) or Advanced Mezzanine Card – Breakout Card (AMC-BOC), or AMC backplane, they are EVM hardware dependent. For example, K2E has 8 SGMII ports. In the K2E EVM, two Ethernet PHYs (PHY1 and PHY2) are connected to SoC SGMII 0 and 1 respectively, to provide a copper interface and routed to a Gigabit RJ-45 connector. The SGMII 2 and 3 of SoC are routed to Port 0 and 1 of the AMC edge connector backplane interface. The SGMII 4 to 7 are routed to RTM connector which can be accessed by RTM BOC. The PA EMAC example by default tests all 8 ports in loopback. To test additional ports in non-loopback, check/modify the gNum_Mac_Ports defined to include the SGMII testing port.

Can PA be used to forward all incoming packets to host?

The design of PA is to use firmware to offload host for classifying packets, the PA has layer 2, 3 and 4 classifications. PA LLD supports two APIs to add MAC LUT1 classification and routing. The application can call either the first generation API Pa_addMac() or the second generation Pa_addMac2() APIs. When using the first API, initialize all the elements of paEthInfo_t with zero and update the routing info paRouteInfo_t with pa_DEST_HOST. When using the second generation API, paEthInfo2_t with validBitMap = 0 and paRouteInfo2_t (in paParamDesc) with pa_DEST_HOST can be passed. Please refer to Pa_addMac and Pa_addMac2() API explanations as provided under the doxygen folder of PA (Or refer to Pa.h interface header file).

6.15.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\PA\docs\doxygen\html\index.h tml
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \drv\PA\docs\ReleaseNotes_PA_LLD. pdf

6.16. SA

6.16.1. Overview

6.16.1.1. Introduction

The Security Accelerator (SA) also known as cp_ace (Adaptive Cryptographic Engine) is designed to provide packet security as part of IPSEC, SRTP, and 3GPP industry standards. The security accelerator low level driver (referred to as the module) provides APIs for the configuration and control of the security accelerator sub-system. The SA low level driver provides an abstraction layer between the application and the Security Accelerator Sub System (SASS). It provides both the system level interface and the channel-level interface with a set of APIs in the driver.

Modes of Operation

Security accelerator library (ti.drv.sa) supports below modes

Protocol Specific Mode: In this mode, standards such as Ipv4/Ipv6 and 3gpp protocols are supported, where command labels are created based on the protocols.

Data Mode: In this mode, user can implement a custom/proprietary protocol mode with the help of APIs provided by SA LLD

6.16.2. User Interface

6.16.2.1. Driver Configuration

The driver configures the SASS subsystem using SA_config_t (system configuration) and Channel Configuration (Sa_ChanConfig_t) structure.

For details about individual fields of this structure and other APIs, see the Doxygen help by opening PDK_INSTALL_DIR\packages\ti\drv\SA\docs\doxygen\html\index.html.

6.16.2.2. APIs

API reference for application:

#include <ti/drv/SA/Salld.h>

6.16.3. Application

6.16.3.1. Examples

Name
Description
Expected Results
SA_Example application
Example demonstrating simple IPSec use case. Reference example for developers
User observes the output printed over the CCS console
SA_UnitTestApplicatio n
Unit Test application to test all APIs
User observes the output printed over the CCS console

6.16.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\sa\docs\doxygen\html\index.h tml
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \drv\sa\docs\ReleaseNotes_SA_LLD. pdf

Note

Although SASS supports 3GPP specific Ciphering and Authentication algorithms such as Kasumi F8/F9 and Snow3G F8, those algorithms are locked out in this standard SA LLD distribution. In order to access 3GPP specific functionalities, one must obtain ETSI licensing as described at https://www.etsi.org/services/security-algorithms/cellular-algorithms and then download the SASS 3GPP Enabler package from TI from the link https://software-dl.ti.com/libs/sa_3gpp_enabler/latest/index_FDS.html

Due to export control restrictions, the SA 3GPP Enabler is a seperate download from the rest of the PROCESSOR-SDK.


6.17. SRIO

6.17.1. Overview

6.17.1.1. Introduction

Driver enables the high-bandwidth system level interconnects. It is intended to offer Gigabyte per second performance levels for chip-to-chip and board-to-board communication.

Modes of Operation

Following modes of operations are supported

Direct I/O: The SRIO packet contains the specific address where the data should be stored or read in the destination device. This means that the source device must have detailed knowledge of the available memory space within the destination device.

Type 9: A destination address is not specified. Instead the Stream ID is used to map the request to a specific memory region by the local (destination) device. TI IP additionally uses Class of Service (COS) as well to further classify the mapping of a request to a memory region.

Type 11: A destination address is not specified, instead, a mailbox identifier is used within the SRIO packet. The mailbox is controlled and mapped to memory by the local (destination) device.

6.17.2. User Interface

6.17.2.1. Driver Configuration

Board Specific Configuration

All board specific configurations eg:enabling and configuring the SRIO SERDES registers and SRIO lane configurations (communication rates, device IDs, etc) are required before calling any driver APIs. Template functions for configuring the SRIO IP and SERDES registers are provided in PDK_INSTALL_DIR\packages\ti\drv\srio\device\<device>\src\. A template function is provided for each soc that supports SRIO.

6.17.2.2. APIs

API reference for application:

#include <ti/drv/srio/srio_drv.h>

OSAL API reference for application:

#include <ti/drv/srio/srio_osal.h>

Init SRIO

Initialize QMSS and CPPI modules...
...
SrioDevice_init();
Srio_init ();
...
/* Start the application Managed SRIO Driver. Refer example/test for appCfg fields */
hAppManagedSrioDrv = Srio_start (&appCfg);

At this point SRIO driver is ready for data transfer on specific instance identified by handle.

Send/Receive APIs

Direct IO:

Srio_sockSend_DIO(Srio_SockHandle srioSock, Srio_DrvBuffer hBuffer, uint32_t size, Srio_SockAddrInfo* to);

Type 9:

Srio_sockSend_TYPE9   (Srio_SockHandle srioSock, Srio_DrvBuffer hBuffer, uint32_t size, Srio_SockAddrInfo* to);

Type 11:

Srio_sockSend_TYPE11  (Srio_SockHandle srioSock, Srio_DrvBuffer hBuffer, uint32_t size, Srio_SockAddrInfo* to);

Receive:

Srio_sockRecv         (Srio_SockHandle srioSock, Srio_DrvBuffer* hDrvBuffer,Srio_SockAddrInfo* from);

6.17.3. Application

6.17.3.1. Examples

Name
Description
Expected Results
Loopback DIO ISR Example Project
The example is a demonstration of the SRIO driver running the SRIO IP Block in loopback mode. The example showcases the use of SRIO DIO sockets using LSU interrupts to indicate the completion of packet transfer.
It is shown how multiple sockets with different Source IDs can post transactions and process the pending interrupt raised by SRIO device.
The application will run through a set of DIO tests. Upon successful completion the following string will be printed “DIO with Interrupts example completed successfully.”
Multicore Loopback Example Project
The example is a demonstration of the SRIO driver while operating in a Multicore environment by running the SRIO IP Block in loopback mode. The test case here showcases the SRIO Driver API being multicore safe and using the SRIO IP peripheral to exchange messages between different cores running on the same device.
In this test case each core performs the role of a producer and consumer. The test starts with Core 1 sending data to Core 2. Core 2 receives and validates the data and sends another data message to Core3; which receives and validates the data and sends another different data message to Core 0. Core 0 then sends a message to Core 1 which is received and validated.
The application will run through a set of tests sending and receiving data between two cores over SRIO. Upon successful completion the following string will be printed “Multicore Test Passed” from each DSP core.
Loopback Test
Unit Test application to test all APIs
The application will run through a set of tests to verify all SRIO LLD APIS. Upon successful completion the following string will be printed “Unit Testing completed successfully.” from each DSP core.
SRIO Benchmarking Test
The SRIO benchmarking example code is created to allow customers to run benchmarks on their own TI EVMs with code that utilizes the SRIO LLD APIs. The benchmarking example code allows the user to run core to core in loopback mode (internal or external) on a single EVM, or board to board using the external interface between two EVMs. This document’s purpose is to explain how measurements are obtained and how to configure the example code for different test scenarios. SRIO physical connectivity or external SRIO switch configuration is beyond the scope of this document.
Review the SRIO Benchmarking Example documentation located in PDK_INSTALL_DIR\packa ges\ti\drv\srio\test\ tput_benchmarking\doc s\SRIO_Benchmarking_E xample_Code_Guide.doc for more information on the tests pass/fail criteria.

6.17.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\srio\docs\doxygen\html\index .html
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \drv\srio\docs\ReleaseNotes_SRIOD river.pdf

6.18. HYPLNK

6.18.1. Overview

6.18.1.1. Introduction

Hyperlink is a point-to-point peripheral. Each device has equal capability to operate on the address space of the other device. This also means that there is no complex enumeration in order to get started.

Modes of Operation

The LLD is intended to bring up the Hyperlink peripheral and open memory mappings.

Interrupts

There is an interrupt generation example (in PDK_INSTALL_DIR/packages/ti/drv/hyplnk/example/cicInterruptExample) which maps and pokes the other device’s CIC (Chip/SOC level interrupt controller) to generate interrupts for data transfers.

The PDK_INSTALL_DIR/packages/ti/drv/hyplnk/example/common/hyplnkIsr.c monitors local interrupts to detect fatal errors. It can also be used for IO interrupts, but there is only one output event that has to be demuxed. Thus for multicore orthogonality, the cicInterruptExample is often better example (because each destination core can have completely independent interrupts).

6.18.2. User Interface

6.18.2.1. Driver Configuration

The driver itself is entirely configured via API at runtime. However, the examples are configured using compiler flags that are in hyplnkPlatCfg.h and hyplnkLLDCfg.h.

The hyplnk_device.c binds the driver to the hardware on the board. It is passed into the driver via the call to Hyplnk_init().

6.18.2.2. APIs

API Call Flow

The API call flow is covered in examplememoryMappedExamplesrchyplnkExample.

They key parts are:

  1. Initialize the LLD via Hyplnk_init().
  2. Configure PLL, PSC and memories via hyplnkExampleSysSetup() which is all example code
  3. Install ISR(s)
  4. Enable the peripheral using sequence in hyplnkExamplePeriphSetup()
  5. Open memory maps using hyplnkExampleAddrMap() as a guide
  6. Exchange data with memcpy or EDMA using mapped address (returned from hyplnkExampleAddrMap).

6.18.3. Application

6.18.3.1. Examples

Hyperlink/hyplnk is supported only on Keystone devices. It is available on 6678, 6657, K2H, K2K, K2E. All examples can be used in either loopback (on any EVM without any special cables or breakout cards) or with two boards. For 6678 or 6657, the required cable is HL5CABLE. For K2H/K2K/K2E, the breakout card is RTM-BOCRT, and the cable is also required. Below is a picture showing how a K2H EVM is connected to a 6678 EVM via breakout card and cable.

../_images/K2-k1-hyplnk.jpg
Name Description EVM Configuration Expected Results
memoryMappedExa mple Memory mapped data exchange with loopback or 2 devices Loopback runs without any extra hardware. See below for details on configuring board-to-board. Link is established and data is exchanged.
cicInterruptExa mple CIC-based interrupt exchange. Loopback runs without any extra hardware. See below for details on configuring board-to-board. Interrupts are sent between ARM Linux Userspace and DSPs.

Setup of multiple EVMs with one instance of CCS

This is only needed for 2 board use cases. See Multi-Emulator_Debug_with_CCS for general configuration of multiple EVMs/emulators within one instance of CCS.

Detailed instructions to run memoryMappedExample

If running with one board, enable loopback via uncommenting hyplnk_EXAMPLE_LOOPBACK in PDK_INSTALL_DIR/packages/ti/drv/hyplnk/example/common/hyplnkLLDCfg.h.

Compile the project for the specific device/evm in use.

For loopback: Load the example with hyplnk_EXAMPLE_LOOPBACK definined onto one board and run. The results should be as below.

For 2 board: Make sure the both boards configuration match each other by checking PDK_INSTALL_DIR/packages/ti/drv/hyplnk/example/common/hyplnkLLDCfg.h:

hyplnk_EXAMPLE_PORT --> which port to use for K2H/K2K/K2E
hyplnk_EXAMPLE_ALLOW_x_LANES --> 0, 1 or 4 lanes
hyplnk_EXAMPLE_SERRATE_xxpxxx --> serdes rate setup

Load the same example on both boards. It is fulling symmetric. No special configuration is needed to distinguish side A and side B. Each side should generate output similar to below.

Detailed instructions to run cicInterruptExample

This only works on devices with A15 running Linux (K2H, K2K, K2E). See PDK_INSTALL_DIR/packages/ti/drv/hyplnk/example/cicInterruptExample/Readme.txt for instructions.

Sample example output

This came from k2h device running in loopback.

Version #: 0x02010005; string HYPLNK LLD Revision: 02.01.00.05:Dec 24 2015:17:48:28
About to do system setup (PLL, PSC, and DDR)
Power domain is already enabled.  You probably re-ran without device reset (which is OK)
Constructed SERDES configs: PLL=0x00000228; RX=0x0046c495; TX=0x000ccf95
system setup worked
About to set up HyperLink Peripheral
============================Hyperlink Testing Port 0
========================================== begin registers before initialization ===========
Revision register contents:
  Raw    = 0x4e902101
Status register contents:
  Raw        = 0x00003004
Link status register contents:
  Raw       = 0x00000000
Control register contents:
  Raw             = 0x00000000
Control register contents:
  Raw        = 0x00000000
============== end registers before initialization ===========
Hyperlink Serdes Common Init Complete
Hyperlink Serdes Lane 0 Init Complete
Hyperlink Serdes Lane 1 Init Complete
Hyperlink Serdes Lane 2 Init Complete
Hyperlink Serdes Lane 3 Init Complete
============== begin registers after initialization ===========
Status register contents:
  Raw        = 0x04402005
Link status register contents:
  Raw       = 0xfdf0bdf0
Control register contents:
  Raw             = 0x00006206
============== end registers after initialization ===========
Waiting 5 seconds to check link stability
Precursors 1
Postcursors: 19
Link seems stable
About to try to read remote registers
============== begin REMOTE registers after initialization ===========
Status register contents:
  Raw        = 0x0440080f
Link status register contents:
  Raw       = 0xfdf0bdf0
Control register contents:
  Raw             = 0x00006202
============== end REMOTE registers after initialization ===========
Peripheral setup worked
About to read/write once
Single write test passed
About to pass 65536 tokens; iteration = 0
=== this is not an optimized example ===
Link Speed is 4 * 3.125 Gbps
Passed 65536 tokens round trip (read+write through hyplnk) in 16829 Mcycles
Approximately 256799 cycles per round-trip
=== this is not an optimized example ===
Checking statistics
About to pass 65536 tokens; iteration = 1
=== this is not an optimized example ===
Link Speed is 4 * 3.125 Gbps
Passed 65536 tokens round trip (read+write through hyplnk) in 16829 Mcycles
Approximately 256799 cycles per round-trip
=== this is not an optimized example ===
Checking statistics
About to pass 65536 tokens; iteration = 2
.
.
.

6.18.4. Debug FAQ

  1. If it seems to not work, check for lError and rError in the status register (hyplnkStatusReg_s). If these appear, it means double ecc error occurred and the link is non functional. This is fatal error. Next look at hyplnkECCErrorReg_s for single (corrected) bit errors. After startup these should increment slowly (order of minutes, hours, days, not seconds or less). If they are incrementing quickly (several times per minute or second), then it means the SERDES coefficients should be calibrated by following the Keystone SERDES UG. See references section.
  2. Note that if the link goes down (uncorrectable ECC error) it is possible for the entire interconnect to lock up. If this occurs, it will not be possible to access any memory even through the JTAG interface (CCS will return errors instead of reading memory, and often disconnect the target). Thus the primary cause of this lockup should be avoided by carefully following the shutdown/reset requirement in section 2.9 of the Hyperlink UG (which is to invoke serial stop, and wait for it to take effect before resetting either endpoint).
  3. Another workaround for ECC single errors is to lower link rate and/or reduce to 1 lane. This can be done by adjusting the commented defines in PDK_INSTALL_DIR/packages/ti/drv/hyplnk/example/common/hyplnkLLDCfg.h.

6.18.5. Additional References

Additional documentation can be found in:

Document Location
Hardware Peripheral Hyperlink Users Guide User Guide
Serdes Users Guide User Guide
CIC Peripheral Users Guide CIC User Guide
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\hyplnk\docs\doxygen\html\ind ex.html
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \drv\hyplnk\docs\ReleaseNotes_HYP LNK_LLD.pdf

6.19. TSIP

6.19.1. Overview

6.19.1.1. Introduction

The TSIP is a multi-link serial interface consisting of a maximum of eight transmit data signals (or links), eight receive data signals (or links), two frame sync input signals, and two serial clock inputs. Internally the TSIP offers multiple channels of timeslot data management and multi-channel DMA capability that allow individual timeslots to be selectively processed.

The module can be configured to use the frame sync signals and the serial clocks as redundant sources for all transmit and receive data signals, or one frame sync and serial clock for transmit and the second frame sync and clock for receive. The standard serial data rate for each TSIP transmit and receive data signal is 8.192 Mbps. The standard frame sync is a one or more bit wide pulse that occurs once every 125 µs or a minimum of one serial clock period every 1024 serial clocks.

At the standard rate and default configuration there are eight transmit and eight receive links that are active. Each serial interface link supports up to 128 8-bit timeslots. This corresponds to an H-MVIP or H.110 serial data rate interface. The serial interface clock frequency can be either 16.384 MHz (default) or 8.192 MHz. The data rate for the serial interface links can also be set to 16.384 Mbps or 32.768 Mbps. The maximum number of active serial links is reduced to four and two, respectively, in these configurations. The serial interface clock frequency can be either 32.768 MHz or 16.384 MHz for 16.384 Mbps serial links, and 65.536 MHz or 32.768 MHz for 32.768 Mbps serial links. Maximum occupation of the serial interface links for the entire TSIP is 1024 transmit and receive timeslots in all configurations.

6.19.2. User Interface

6.19.2.1. Driver Configuration

TSIP configuration involves configurations for desired stagger phase of a TSIP timeout, using Tsip_configPhase() API. For details about individual fields of this structure, see the Doxygen help by opening PDK_INSTALL_DIR\Packages\ti\drv\TSIP\docs\doxygen\html\index.html.

6.19.2.2. APIs

API reference for application:

#include <ti/drv/tsip/tsip.h>

6.19.3. Application

6.19.3.1. Examples

Name Description Expected Results
tsip_Example application
Example demonstrating sample tsip test. Reference example for developers
User observes the output printed over the CCS console
tsip_UnitTestApplicat ion
Unit Test application to test all APIs
User observes the output printed over the CCS console

6.19.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\TSIP\docs\doxygen\html\index .html
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \drv\TSIP\docsReleaseNotes_TSIP. pdf

6.20. MCBSP

6.20.1. Overview

6.20.1.1. Introduction

The multichannel buffered serial port (MCBSP) peripheral allows direct interface to other TI DSPs, codecs, and other devices in a system. The primary use for the MCBSP is for audio interface purposes. The following sub sections explain the hardware (MCBSP peripheral) and software context of the MCBSP LLD.

The device driver exposes a set of well-defined APIs which are used by the application layer to send and receive data via the MCBSP peripheral. The driver also exposes a set of well-defined OS abstraction APIs which are used to ensure that the driver is OS independent and portable. The MCBSP driver uses the CSL MCBSP register layer for all MCBSP MMR access. The MCBSP driver also interfaces with the EDMA3 library to be able to transfer data to and from MCBSP peripheral and data memory.

6.20.2. User Interface

6.20.2.1. Driver Configuration

The MCBSP Driver initialization API needs to be called only once and it initializes the internal driver data structures like device objects. Application developers need to ensure that they call the MCBSP Driver Init API before they call the MCBSP Device Initialization. Following API is used to initialize the MCBSP Driver

int32_t mcbspInit (void)

MCBSP Peripheral Configuration The MCBSP driver provides a sample implementation sequence which initializes the MCBSP IP block. The MCBSP Device initialization API is implemented as a sample prototype:

void McbspDevice_init (void)

For details about individual fields of this structure, see the Doxygen help by opening PDK_INSTALL_DIRPackagestidrvMCBSPdocsdoxygenhtmlindex.html.

6.20.2.2. APIs

API reference for application:

#include <ti/drv/MCBSP/mcbsp_drv.h>

6.20.3. Application

6.20.3.1. Examples

Name Description
MCBSP_Example application Example demonstrating sample MCBSP loopback test. Reference example for developers

6.20.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\MCBSP\docs\doxygen\html\inde x.html
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \drv\MCBSP\docs\ReleaseNotes_MCBS P.pdf

6.21. EMAC

6.21.1. Introduction

EMAC driver provides a well defined API layer which allows applications to use the EMAC peripheral to control the flow of packet data from the processor to the PHY and the MDIO module to control PHY configuration and status monitoring.

6.21.2. Driver Configuration

6.21.2.1. Board Specific Configuration

All the board specific configurations eg:enabling and pin-mux of RGMII/MDIO pins should be performed before calling any driver APIs.By default Board_Init() API supports all initialization sequence for TI supported EVMs.Refer Processor SDK RTOS Board Support for additional details.

Once the board specific configuration is complete driver API emac_open() can be called to initialize driver

6.21.2.2. EMAC Configuration Structure

The EMAC_soc.c file binds driver with hardware attributes on the board through EMAC_Cfg structure. This structure must be provided to EMAC driver. It must be initialized before the emac_open() function is called. Prior to calling emac_open, the address of the descriptor region base to be inserted into the QMSS memory region MUST be provided by the user application and updated into the EMAC_HwAttrs_V1 structure which is part of the EMAC_Cfg. EMAC_socGetInitCfg() can be invoked to get the EMAC initial configuration and EMAC_socSetInitCfg to update the configuration as illustrated below.

EMAC_socGetInitCfg(0, &emac_cfg);
/* Need to update the descriptor base address */
emac_cfg.p_desc_base = &gHostDesc;
/* Now set the config after updating desc base address */
EMAC_socSetInitCfg(0, &emac_cfg);

For details about individual fields of this structure, see the Doxygen help by opening PDK_INSTALL_DIRpackagestidrvuartdocsdoxygenhtmlindex.html.

6.21.3. APIs

API reference for application:

#include <ti/drv/emac/emac_drv.h>

6.21.3.1. EMAC Open

API to allow the calling application to supply a valid port number and open configuration data. Note that providing a descriptor base address is the code snippet below is only required for Keystone devices (at this time only EVMK2G is supported) which is required to set up the Host descriptor memory region in the QMSS sub-system.

...
Board_init(boardCfg);
EMAC_socGetInitCfg(0, &emac_cfg);
/* Need to update the descriptor base address */
emac_cfg.p_desc_base = &gHostDesc;
/* Now set the config after updating desc base address */
EMAC_socSetInitCfg(0, &emac_cfg);
port_num = 0;
/* Need to populate open_cfg structure with application specific configuration */
openReturn = emac_open([port_num, &open_cfg))

6.21.3.2. EMAC Config

API to allow the calling application to provide RX filter configuration. This API is currently only supported for C6657 & OMAPL13x SOCs.

/* fill in cfg_info structure */
configReturn = emac_config(port_num, &cfg_info);

At this point EMAC driver is ready to send and receive packets.


6.21.3.3. EMAC Close

API to allow user application to close an opened EMAC port. This API will release all resources allocated during the call to emac_open().

EMAC Get Statistics

API to allow user application to retrieve statistics for specified port

emac_get_statistics(port_num, * p_stats)

6.21.3.4. EMAC Receive Packet Poll

API (emac_pkt_poll) to provide a while(1) loop to receive packets. This API must be called within a task context as it is blocking API. Internally, this API will PEND on a semaphore until it it POSTED by the Hwi Interrupt Handler. The Hwi interrupt handling is setup during the call to the emac_open API at which time the user application, as part of the open, configures a receive packet callback. Once there is a received packet, the emac_pkt_poll function will invoke this callback to provide the packet to the user application and resume PENDING on a semaphore until there is another packet to receive. This API will not return to the user application.


6.21.3.5. EMAC Send

API to allow user application to send packet on opened EMAC port.

retVal = emac_send(port_num, pkt_desc);

6.21.3.6. EMAC Poll

API to allow user application to poll the status of opened EMAC port. Status info will be returned in the link_info structure.

emac_poll(port_number, &link_info);

6.21.4. Example

Name Description Expected Results
EMAC_BasicExample_evm K2G

EMAC Loopback test at CPSW switch interface. Reference example for developers

Example demonstrates loopback capability by sending dummy broadcast packet to CPSW switch. Unit test registers receive packet callback routine with LLD to be called for RX packet. Call back routine will extract packet received, perform simple memory comparison against packet sent for integrity check. Unit test will iterate over configured packet count for packet transmission and reception check.

Unit Test will print “All tests have passed” via UART console.
EMACLoopback_testProj ect (for DRA7xx, C6657, OMAPL137 & OMAPL138)

EMAC Loopback test at CPSW switch interface. Reference example for developers

Example demonstrates loopback capability by sending dummy broadcast packet to CPSW switch. Unit test registers receive packet callback routine with LLD to be called for RX packet. Call back routine will extract packet received, perform simple memory comparison against packet sent for integrity check. Unit test will iterate over configured packet count for packet transmission and reception check.

This example needs to be run on the OMAPL137 and OMAPL138 platforms using external loopback cable. OMAPL137 EVM is having two Ethernet ports. Connect the loopback cable to the port 1 (ENET-P1) while running the loopback example.

Unit Test will print “Loopback Test completed successfully on core 0” via CCS console for C6657 and on UART serial console for OMAPL13x.
EMAC_PktInspectionExa mple (for all DRA7xx devices)

This demonstrates how to write an application to filter Ethernet packets based on IP address

Prerequisites:

  • Install the packETH utility (v 1.8.1) on a Linux PC. The packETH tool is available for Windows as well, but not all features are supported

  • Download the test PCAP files

    and update the source and dest MAC address of the PC and EVM to be used in the test. The tcprewrite utility can be used to set the new MAC addresses (i.e. tcprewrite –enet-smac=<PC-MA

C-address>
–enet-dmac=<EVM-M
AC-address>
-i ./ip1_test.pcap -o ./ip1_test.pcap)

Steps:

  • Launch the packETH utility on the Linux PC with root permissions
  • Go to the “Gen-S” tab of the packETH utility and select the PCAP files to be used
  • Set the transfer rate for each PCAP file (i.e. 200 Mbit/s and 150 Mbit/s)
  • Set the total packets to transfer to 500000
  • Load and run the EMAC packet inspection application to the IPU1 core
  • Hit the “Send” button on the packETH utility to start streaming
  • The packet streaming should last for few seconds

Pass criteria:

  • The total packet sent for each stream is shown at the bottom of the packETH widow. The packet stream statistics must match the packet statistics printed by the DUT via serial port
  • The packet inspection utility periodically prints the EMAC statistics, which include DMA overruns, underruns and other error. No errors should be seen during the transfer.

Fail criteria:

  • Packet count mismatch between packETH utility and counters from the IPU1 application
  • Any EMAC errors reported by the IPU1 application

6.21.5. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)packagesti drvemacdocsdoxygenhtmlindex .html
Release Notes $(TI_PDK_INSTALL_DIR)packagesti drvemacdocsReleaseNotes_EMAC_ LLD.pdf

6.22. MCASP

6.22.1. Overview

6.22.1.1. Introduction

The multichannel audio serial port (McASP) functions as a general-purpose audio serial port optimized for the needs of multichannel audio applications. The McASP is useful for time-division multiplexed (TDM) stream, Inter-Integrated Sound (I2S) protocols, and intercomponent digital audio interface transmission (DIT).The multichannel buffered serial port (McASP) peripheral allows direct interface to other TI DSPs, codecs, and other devices in a system. The following sub sections explain the hardware (McASP peripheral) and software context of the McASP LLD.

The device driver exposes a set of well-defined APIs which are used by the application layer to send and receive data via the McASP peripheral. The driver also exposes a set of well-defined OS abstraction APIs which are used to ensure that the driver is OS independent and portable. The McASP driver uses the CSL McASP register layer for all McASP MMR access. The McASP driver also interfaces with the EDMA3 library to be able to transfer data to and from McASP peripheral and data memory.

6.22.2. User Interface

6.22.2.1. Driver Configuration

The McASP driver provides a sample implementation sequence which initializes the MCASP IP block. The McASP Device initialization API is implemented as a sample prototype:

void McaspDevice_init (void)

The function initializes all the instance specific information like base address of instance CFG registers, FIFO address for the instance, TX and RX CPU event numbers, TX and RX EDMA event numbers etc.

For details about individual fields of this structure, see the Doxygen help by opening PDK_INSTALL_DIRPackagestidrvmcaspdocsdoxygenhtmlindex.html.

int32_t Mcasp_socGetInitCfg(uint32_t index, Mcasp_HwInfo *cfg)

The function obtains the soc configuration parameters such as interrupt numbers, mux configuration parameters etc.

int32_t Mcasp_socSetInitCfg(uint32_t index, const Mcasp_HwInfo *cfg)

The function set the soc configuration parameters such as interrupt numbers, mux configuration parameters etc.

6.22.2.2. APIs

Refer to below API files:

#include <ti/drv/mcasp/mcasp_drv.h>
#include <ti/drv/mcasp/soc/mcasp_soc.h>

McASP Buffer formats

The McASP driver provides various buffer formats for sending the data to/from the audio device. The differences between these formats arise from the way the audio samples are collected from various serializers and their timeslots and arranged in the system’s memory. This way the application can choose to run audio processing algorithms over the data without the need for re-arranging those data every frame. The buffer format is provided in the Mcasp_ChanParams.dataFormat in the form of Mcasp_BufferFormat defined in mcasp_drv.h The below section provides an overview of the various formats. In the explanatory diagrams in each section, McASP controller recieves samples in frame intervals denoted by t1,t2..tn. The McASP driver collects these and arranges those samples in the memory in various formats in to the host’s System memory. We have chosen 32 bit samples and 32-bit word addresses throughout for simplicity.

Mcasp_BufferFormat_1SER_1SLOT

This is applicable if only one serializer and one timeslot is used. The samples are ordered in the order they received or sent.

../_images/1SLOT_1SER.PNG

Mcasp_BufferFormat_1SER_MULTISLOT_INTERLEAVED

This is applicable if multiple slots are used with one serializer. The samples from the different timeslots are stored interleaved in the memory as below. Different timeslots’ samples are denoted by different colors and are labelled t1,t2..tn according to the time they arrive at the serializer.

../_images/1SER_MULTISLOT_INTERLEAVED.PNG

Mcasp_BufferFormat_1SER_MULTISLOT_NON_INTERLEAVED

This is applicable if multiple slots are used with one serializer. The samples from the different timeslots are grouped together on the basis of the timeslot and stored in the memory as shown below. Different timeslots’ samples are denoted by different colors and are labelled t1,t2..tn according to the time they arrive at the serializer.

../_images/1SER_MULTISLOT_NON_INTERLEAVED.PNG

NOTE: if the non-interleaved format is used, the Mcasp_ChanParams-> hwFifoEventDMARatio must be set to 1.

Mcasp_BufferFormat_MULTISER_1SLOT_SER_INTERLEAVED

This is applicable if multiple serializers are used with one time slot is used for each of the serializers. The samples from the different serializers are stored in the memory in interleaved fashion as shown below Different serializers’ samples are denoted by different colors and are labelled S1,S2..Sn according to the time they arrive at the serializer.

../_images/1SER_MULTISER_1SLOT_SER_INTERLEAVED_2.PNG

Mcasp_BufferFormat_MULTISER_1SLOT_SER_NON_INTERLEAVED

This is applicable if multiple serializers are used with one timeslots each per serializer. The samples from the different timeslots are grouped together on the basis of the serializer and stored in the memory as shown below Different serializers’ samples are denoted by different colors and are labelled S1,S2..Sn according to the time they arrive at the serializer.

../_images/1SER_MULTISER_1SLOT_SER_NON_INTERLEAVED.PNG

Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_1

This is applicable if multiple serializers are used and each serializer containing multiple timeslots. The samples are stored in the memory interleaved based on serializer and timeslots as shown below. In this example, there are 3 serializers and 2 timeslots per serializers whose samples are noted by Ln (left) and Rn (right). Different serializers’ samples are denoted by different colors.

../_images/1SER_MULTISER_MULTISLOT_SEMI_INTERLEAVED_1_UPDATED.PNG

Mcasp_BufferFormat_MULTISER_MULTISLOT_SEMI_INTERLEAVED_2

This is applicable if multiple serializers are used and each serializer containing multiple timeslots. The samples are grouped based on the serializer and within one serializer, the timeslots are interleaved as shown below. In this example, there are 3 serializers and 2 timeslots per serializers whose samples are noted by Ln (left) and Rn (right).Different serializers’ samples are denoted by different colors.

../_images/1SER_MULTISER_MULTISLOT_SEMI_INTERLEAVED_2.PNG

NOTE: if the non-interleaved format is used, the Mcasp_ChanParams-> hwFifoEventDMARatio must be set to 1.

Mcasp WordBits Selection

With all the frame formats explained above, there is an option to choose which bits to pack from the 32-bit serializer data obtained from/to the McASP serializer, when the word size is less than the slot size. This option is exercised by setting the Mcasp_chanParams->wordBitsSelect to Mcasp_wordBitsSelect_LSB/Mcasp_wordBitsSelect_MSB.

If the default Mcasp_wordBitsSelect_LSB option is selected, the LSBs are packed in to the system memory.

Below is an example of word size = 16bits and slot size = 32 bits and the Mcasp_wordBitsSelect_LSB option is used. On the receiving side, the serializer holds the 32 bit data whose LSB 16 bits are picked up and packed in to the system memory. The MSB 16 bits are ignored.

../_images/WordSelect_LSB.PNG

If the Mcasp_wordBitsSelect_MSB option is used, the serializer’s MSB-16bits are packed in to the system memory. The LSBs are ignored.

../_images/WordSelect_MSB.PNG

Priming

Applications using McASP driver often might send/receive one or two transfers via McASP before sending the application data in/out of McASP through the driver. This would internally set up transfer request queues so that the application can seamlessly send/receive data without the possibility of underrun. This process, a.k.a priming is used in the example application provided with the Processor SDK. In this example two frames are sent/received prior to submitting the application’s audio data to the McASP driver. The number of transfer requests to prime is application dependent and some applications where there may be a lot of delay between transfer requests, enough to cause an underrun, the priming factor could be higher.

6.22.3. Application

6.22.3.1. Examples

Name
Description
Expected Results
AIC31 Stereo loopback
Example demonstrating sample McASP loopback . Reference example for developers
Audio sent in to the EVM being played out via the stereo output of the EVM
Device loopback
Example demonstrating sample McASP device loopback . Reference example for developers
Digital ramp pattern sent to McASP and getting looped back internally using device loopback
AudioEQ example
Example demonstrating stereo audio equalization using using biquad filters . Reference design for developers. TI Design Guide: TIDEP0069
Three band Equalization of stereo channel using biquad filters with gain control using serial console inputs

Introduction

The sample application demonstrates the use of the MCASP driver for audio playback. The application uses McASP LLD, and programs the AIC codec on the EVM to send and receive the audio input. The audio received from the AIC codec is loop back-ed at the application and sent back to the AIC codec via MCASP LLD.

Audio test setup

Please ensure the below before running the demo

  1. Connect the EVM’s stereo audio input to the PC’s stereo audio output
  2. Connect the EVM’s stereo audio output to powered speakers. Please make sure the amplification on the speakers is high enough for the audio output to be heard

Building and running the Example

  1. Run pdkProjectCreate to create the MCASP_Audio_<evm>_<device>ExampleProject
  2. Load the project on to CCS and build the same.
  3. Build the example
  4. Load the MCASP_Audio_<evm>_<device>ExampleProject
  5. Run the example

Testing the example

  1. Play an audio file on the PC.
  2. You should be able to hear the same audio on the speakers connected to the EVM. It is the PC’s audio output which is loop backed at the EVM’s MCASP example outputted to the speakers.

NOTE: Please make sure the speakers’ output volume is high enough for the audio to be audible.

6.22.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\mcasp\docs\doxygen\html\inde x.html
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \drv\mcasp\docs\ReleaseNotes_MCAS P_LLD.pdf
Software design Specification $(TI_PDK_INSTALL_DIR)\packages\ti \drv\mcasp\docs\MCASP_LLD_SDS.pdf

Templates used on this page:

Return to Processor SDK RTOS MCASP.

Navigation menu Log inRequest accountPageDiscussionReadView sourceView history

Search Go Main Page All pages All categories Recent changes Random page Help Toolbox What links here Related changes Special pages Page information This page has been accessed 927 times. Privacy policyAbout Texas Instruments WikiDisclaimersTerms of UseCreative Commons Attribution-ShareAlike Powered by MediaWiki


6.23. PM

6.23.1. Overview

6.23.1.1. Introduction

The Power Management (PM) low level driver provide power and thermal management capabilities for RTOS applications.

Supported Devices

Device A15 A8 A9 C66x M4 Tested On
AM57xx X     X X AM572x GP EVM, AM571x GP EVM
AM335x   X       AM335x GP EVM
AM437x     X     AM437x GP EVM
K2G X     X   K2G EVM

6.23.2. User Interface

6.23.2.1. Driver Configuration

Board Specific Configuration

The following board-specific actions must take place prior to calling any PM Power APIs:

  • A board-specific I2C implementation must be registered with the PM HAL layer
  • The PMIC Ops structure matching the executing device’s PMIC must be registered with PM HAL layer
  • Device clock rates must be initialized through the PM LIB layer

For working examples of how to implement the listed items, see the “main” functions of any PM example in [PDK_INSTALL_DIR]\packages\ti\drv\pm\examples.

PM Configuration Structure

The pmsrcpmrtosprcmPowerDevice.c file configures the PM driver through the PowerDevice_config structure. This structure must be provided to PM driver. The structure is a global defined within PowerDevice.c and must be initialized prior to calling Power_init(). The structure cannot be changed after calling Power_init(). For details about individual fields of this structure, see the Doxygen help by opening [PDK_INSTALL_DIR]\packages\ti\drv\pm\docs\doxygen\html\index.html.

6.23.2.2. APIs

The following lists the main application interfaces; see the end of this page for a link to the API Reference Manual with full details.

PM TI RTOS base API reference for applications can be found in below file:

#include <ti/drv/pm/Power.h>  /* Contains the core TI RTOS Power implementation APIs */

PM TI RTOS extended API reference for applications can be found in the below file:

#include <ti/drv/pm/PowerExtended.h>  /* Contains TI RTOS Power API extensions such as thermal management */

PM TI RTOS device-specific API reference for applications can be found in the below file:

#include <ti/drv/pm/PowerDevice.h>  /* Contains device-specific TI RTOS Power API definitions and structures */

6.23.3. Application

6.23.3.1. Examples

Name
Description
Expected Results
PM RTOS Application
Example demonstrating power management use cases. Reference example for developers
Application cycles the processor running the application through various power states using the PM APIs. User observes the output printed over the device’s UART connection.
Note: The example should be run in “Free Run” mode when loaded and executed in Code Composer Studio in order to prevent sleep API testing interruptions from the JTAG.
Use the following steps to execute the application on the AM57xx’s M4 and C66 processors in Code Composer Studio:
  • Connect to CortexA15_0 waiting until the GEL file initialization completes
  • Run the GEL: Scripts–>AM572x MULTICORE Initialization–>A
M572x_MULTICORE_Enabl eAllCores - Connect to M4_IPU1_C0 or the C66xx_DSP1 - Load the PM RTOS application’s M4 or c66 executable - Free run the M4_IPU1_C0 or the C66xx_DSP1
PM RTOS Thermal Application
Example demonstrating thermal management use case. Reference example for developers
Application sets high and low thermal set points using the PM APIs. The set points are triggered by internally heating up the processor. User observes the output printed over the device’s UART connection.
Use the following steps to execute the application on the AM57xx’s M4 and C66 processors in Code Composer Studio:
  • Connect to CortexA15_0 waiting until the GEL file initialization completes
  • Run the GEL: Scripts–>AM572x MULTICORE Initialization–>A

M572x_MULTICORE_Enabl eAllCores - Connect to

M4_IPU1_C0 or the C66xx_DSP1
  • Load the PM RTOS Thermal application’s M4 or c66 executable
  • Run the M4_IPU1_C0 or the C66xx_DSP1
PM Measurement Application
Menu-based application allowing selection of processor OPPs and benchmark tests.
Application allows the user to control the processor’s OPP settings via the PM driver. The application also allows the user to select execution of the Dhrystone benchmark for performance and power profiling under different OPP settings. The application’s menu is printed over the device’s UART connection. | Note: The measurement application is only supported on the AM335x device at the moment.

6.23.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\pm\docs\doxygen\html\index.h tml
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \drv\pm\docs\ReleaseNotes_PM_LLD. pdf

6.24. RM

6.24.1. Overview

6.24.1.1. Introduction

The Resource Manager (RM) is delivered as part of Processor-SDK as a means for managing system resource contentions. RM has the ability to allocate system resources within a software architecture based on sets of allocation rules. Resources can be allocated to anything from a device core, to an OS task or process, to a specific software module. RM’s resource management is defined by the RM configuration parameters and how RM is integrated within a software framework. The RM source code is device agnostic. The RM configuration parameters are device specific allowing RM to function on any processor capable of compiling and executing a C binary.

RM Instance Types

Resource Manager is an instance-based architecture. Integrating RM into a system consists of creating a set of RM instances, connecting these instances via message-passing mechanisms, and then using the instances to request resources for cores, processes, tasks, modules, etc. There are no restrictions on where a RM instance can be created as long as the means exist to connect the instance to other RM instances within the system.

There are five instance types

  1. Server: Manages all defined system resources. Services resource requests received from connected Client Delegates and Clients.
  2. Client Delegate (CD): Acts as a low-request-latency proxy for the RM Server, managing resources provided by the RM Server. Services resource requests received from connected Clients.
  3. Client: Front-end for receiving/responding to resource requests from application. Forwards resource requests to Server, or CD, for servicing. Returns allocated resources to application once response is received from Server or CD.
  4. Shared Server: Same as the standard Server except all resource data structures are stored in shared memory allowing direct access from Shared Client instances.
  5. Shared Client: Same as Client except has direct access to the Server resource data structures via shared memory. Useful for low latency requests but not as robust from a software architecture perspective given shared memory MUST be available and used in order for Shared Server-Clients to function.

6.24.2. User Interface

6.24.2.1. Driver Configuration

Resource Configuration

The RM Server instance must be provided a resource list and allocation policy at initialization time. The resource list and allocation policy are specified in the open source flattened device tree format. Device specific resource list and allocation policy files are provided in [PDK_INSTALL_PATH]/packages/ti/drv/rm/device/[SoC]/.

The Client Delegate and Client instances do not require a resource list and allocation policy at initialization.

Transport Configuration

RM instances must be attached to one another using a message passing mechanism. This mechanism can be shared memory, software/hardware queues, sockets or any other method capable of sending and receiving data packets between endpoints on the SoC.

An example transport implementation used by many PDK test applications is available in [PDK_INSTALL_PATH]/packages/ti/drv/rm/test/rm_transport_setup.c. The implementation uses an IPC shared memory transport to connect an RM Server to RM Clients on multiple DSP cores.

6.24.2.2. APIs

RM instance init/delete/status API reference for application:

#include <ti/drv/rm/rm.h>

RM instance transport API reference for application:

#include <ti/drv/rm/rm_transport.h>

RM instance service request/response API reference for application:

#include <ti/drv/rm/rm_services.h>

RM Server interface API reference for application:

#include <ti/drv/rm/rm_server_if.h>

6.24.3. Application

6.24.3.1. Examples

Name
Description
Expected Results
RM DSP BIOS Test application
Unit Test application exercising APIs and the different service request/response mechanisms across the Server, Client Delegate, and Client instances.
Application successfully completes on two DSP cores.
RM Memory DSP BIOS Test application
Unit Test application to test for memory leaks during resource request/free operations.
Application successfully completes with no memory leaks on two DSP cores.
RM Shared DSP BIOS Test application
Unit Test application exercising Shared Server/Client APIs and resource allocation in a Shared Server/Client architecture.
Application successfully completes with no memory leaks on two DSP cores.
RM DSP BIOS Multi-Threaded Test application
Unit Test application verifying service request/response mechanism in a multi-threaded architecture.
Application successfully completes with no memory leaks on a single DSP core.
RM ARM Linux Test application
Unit Test application exercising APIs and the different service request/response mechanisms across the Server, Client Delegate, and Client instances.
Application successfully completes when run from Linux user-space.
RM ARM Linux Multi-Threaded Test application
Unit Test application verifying service request/response mechanism in a multi-threaded architecture.
Application successfully completes when run from Linux user-space.
Combined DSP BIOS & ARM Linux Test application
Unit Test application verifying service request/response mechanism over a heterogeneous processor boundary. RM Clients on two DSP cores request resources from an RM Server running in Linux user-space.
Application successfully completes with no memory leaks on two DSP cores.

6.24.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\rm\docs\doxygen\html\index.h tml
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \drv\rm\docs\ReleaseNotes_RM.pdf
Resource Manager User Guide Processor SDK Resource Manager

6.25. GPMC

6.25.1. Overview

6.25.1.1. Introduction

The general-purpose memory controller (GPMC) is an unified memory controller dedicated to interfacing external memory devices:

  • Asynchronous SRAM-like memories and application-specific integrated circuit (ASIC) devices
  • Asynchronous, synchronous, and page mode (only available in non-multiplexed mode) burst NOR flash devices
  • NAND Flash

Driver supports two types of transfers with data path to external memory device configured to be 16- or 8-bit:

  • Read
  • Write
In addition driver supports following modes of operation:
  • GPMC_MODE_BLOCKING: By default, driver operates in blocking mode. In blocking mode, a Task’s code execution is blocked until transaction is complete. This ensures only one transaction operates at a given time. Driver supports both interrupt or non-interrupt based blocking modes.
  • GPMC_MODE_CALLBACK In callback mode, an GPMC transaction functions asynchronously, which means that it does not block a Task’s code execution. After an GPMC transaction is complete, GPMC driver calls a user-provided hook function. Only interrupt based callback is supported.

In NAND flash mode, driver supports following ECC algorithms:

  • BCH code 8-bit
  • HAMMING code 1-bit

6.25.2. User Interface

6.25.2.1. Driver Configuration

Board Specific Configuration

All the board specific configurations eg:enabling and pin-mux of GPMC pins should be performed before calling any driver APIs.By default Board_Init() API supports all initialization sequence for TI supported EVMs.Refer Processor SDK RTOS Board Support for additional details.

Once the board specific configuration is complete driver API GPMC_init() can be called to initialize driver

GPMC Configuration Structure

GPMC_soc.c file binds driver with hardware attributes on the board through GPMC_config structure. This structure must be provided to GPMC driver. It must be initialized before the GPMC_init() function is called and cannot be changed afterwards. For details about the individual fields of this structure, see the Doxygen help by opening PDK_INSTALL_DIR\packages\ti\drv\gpmc\docs\doxygen\html\index.html.

6.25.2.2. APIs

API reference for application:

#include <ti/drv/gpmc/GPMC.h>

 Sample code for initiating GPMC transaction:

...
Board_init(boardCfg);
...
...
gpmc = GPMC_open(peripheralNum, &gpmcParams);
...
...

/* Initiate GPMC transfers. Refer Example for details
*/
transferOK = GPMC_transfer(gpmc, &gpmcTransaction);
if (!transferOK) {
/* GPMC transaction failed */
}

6.25.3. Application

6.25.3.1. Examples

Refer Release Note for GPMC support across different EVMs

Name
Description
Expected Results
GPMC NOR/NAND Read Example Application
Simple example to read data from GPMC NOR/NAND flash on board.

Following prints will come on console based on pass/fail criteria:

Pass criteria:

GPMC flash device ID: 0x##, manufacturer ID: 0x##

GPMC flash read test passed.

All tests have passed.

GPMC NOR/NAND test application
Driver Unit Test application to test GPMC NOR/NAND flash read/erase/write

Following prints will come on console based on pass/fail criteria:

Pass criteria:

GPMC flash device ID: 0x##, manufacturer ID: 0x##

GPMC flash block erase test passed.

GPMC flash write test passed.

GPMC flash read test passed.

All tests have passed.

     

Note

  1. GPMC Test Application supports write test, by default write test is disabled, user can enable the write test by defining TEST_GPMC_FLASH_WRITE in test/src/GPMC_board.h.
  2. In GPMC_Test_icev2AM335x, J5 pin2 & 3 should be shorted on iceV2AM335x board in order to test GPMC NOR flash.

3. In GPMC_Test_evmAM437x, J2 pin1 & 2 should NOT be shorted on evmAM437x board in order to test GPMC NAND flash.

6.25.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\gpmc\docs\doxygen\html\index .html
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti \drv\gpmc\docs\ReleaseNotes_GPMC_ LLD.pdf

6.26. VPS Drivers

6.26.1. Overview

6.26.1.1. Introduction

VPS (Video Processing SubSystem) video Drivers allow users to make use of all video hardware features like 1080P capture, HDMI/LCD/SDTV display, deinterlacing, scaling. A user can use the drivers in many different ways like multi-channel capture, memory to memory processing, display and so on. This document has detailed API description that user’s can use to make use of the VPS drivers.

VPS consists of following modules

  • Video Input Port (VIP) - for video capture functions for the device
  • Video Processing Engine (VPE)- for video operations such as color space convertion, deinterlacing, scaling and chroma upsampling features.
  • Display SubSystem (DSS) - for LCD outputs on three parallel interfaces (DPI1, DPI2, and DPI3) and HDMI

6.26.2. User Interface

6.26.2.1. Driver Configuration

Board Specific Configuration

All board specific configurations eg:enabling clock and pin-mux for UART/display/vip pins are required before calling any driver APIs. The board specific configurations are implemented under <pdk>/ti/drv/vps/src/boards/src folder.

VPS Configuration Structure

For details about individual fields of VPS library structure, see the Doxygen help by opening PDK_INSTALL_DIR\packages\ti\drv\vps\docs\doxygen\html\index.html.

6.26.2.2. APIs

The VPS driver API can be broadly divided into the following categories

  • FVID2 API - API used to create, control and use the different VPS drivers
  • VPS (Video Processing Sub-system) API - API for all video drivers
  • VPS Control Driver API
  • VPS Capture API - API for video capture drivers
  • VPS VIP Capture API - API specific to VIP capture driver
  • VPS DSSWB Capture API - API specific to DSS WB capture driver
  • VPS Display API - API for video display drivers
  • VPS Display Controller API - API for controlling and configuring VENCs in the display subsystem
  • VPS Memory to Memory (M2M) API - API for memory to memory drivers
  • M2M VPE API - API specific to VPE M2M driver
  • External Device API - API for controlling external video devices like video decoders, video encoders, video filters, IO expanders, Ultra-sonic sensors
  • Platform Specific API - API for platform/board specific control, like setting pin muxes, clocks etc
  • Board Specific API - API for board specific features.

In addition to above drivers the VPS package also includes many sample examples which show how to use the drivers in different ways. Many of these sample examples use a common set of APIs which a user may find useful to refer to for use in their final application.

API reference for application:

#include <ti/drv/vps/include/vps_<func>.h>

6.26.3. Application

6.26.3.1. Examples

Name
Description
Expected Results
Display Dss application
Example demonstrating simple display yuyv or bgr frames to the LCD use case. Reference example for developers
Application prompts user to select the test case input in CCS console.
Display Dss application (Bare Metal)
Example demonstrating simple display yuyv or bgr frames to the LCD use case for bare metal use cases. Reference bare metal example for developers
Application prompts user to select the test case input in CCS console.
Display Dss WB application
Example demonstrating simple display Write Back (WB) yuyv or bgr frames to the LCD use case. Reference example for developers
Application prompts user to select the test case input in CCS console.
Loopback application (Capture and Display application)
Example demonstrating simple capture and display yuyv frames from camera to the LCD use case. Reference example for developers
Application prompts user to select the test case input in CCS console, please select ov2659 camera for idkAM57x and OV1063x for evmAM572x test cases.
Loopback application Bare metal(Capture and Display application)
Example demonstrating simple capture and display yuyv frames from camera to the LCD use case for bare metal. Bare Metal reference example for developers
Application prompts user to select the test case input in CCS console, please select ov2659 camera for idkAM57x and OV1063x for evmAM572x test cases.

Note

* Starting from Processor SDK 4.2 release, idkAM574x support is added for VPS.
* Starting from Processor SDK 4.2 release, oV1063x camera part support is added for AM572x - GP evm (older Aptina MT9T11 camera is never supported).
* Starting from Processor SDK 3.2 release, osd101t2587 lcd panel is supported (new part) along with osd101t2045 lcd panel (old part) on idkAM572x
  and idkAM571x boards for all display subsystem examples.
* The bare metal examples are added starting from Processor SDK 4.0 release
* Some of the clocks such as 32KHz Sync clock are directly tied to A15 core and need that core to be running. Hence while testing the code on other cores
  such as DSP/IPU, please make sure to disconnect the ARM core after connecting the ARM core & running the GEL files to enable the other cores and before
  loading the executable on that core.

6.26.4. Additional References

Document Location
API Reference Manual $(TI_PDK_INSTALL_DIR)\packages\ti \drv\vps\docs\doxygen\html\index. html

6.26.5. Building VPS examples

  • VPS examples and dependent libraries are built from the top level pdk makefile after the environment setup is done using the pdksetupenv.sh(bat) file.
  • cd <pdk>/packages
  • pdksetupenv.bat (sh)
  • make vps  : to build vps examples under <pdk>/ti/packages/binary folder
  • make vps_clean : to clean the vps and vps examples.

6.26.6. VPS examples

6.26.6.1. Display DSS Example

Description

The example exploits the DISPC (Display Controller) and LCD/HDMI outputs available in the SoC. When run, the test outputs multiple options to select between to demonstrate the various capacity of the display subsystem. There is also option to select “Auto Run”, when selected runs all the tests in sequential manner. The example works on outputing a pre-loaded video frames of YUV422I and BGR888 formats to DP1, DP2 and DP3 parallel interfaces and also to HDMI output observed on TV set, from VID1, VID2, VID3 and GFX pipelines. The example also demonstrates displaying videos combined from GFX and other VID pipelines to DPI1 LCD output. The example is also enhanced to show the display controler scaling features. Test that exploits the scalar unit to show all possible allowed scaling. Maximum scaling ratio supported is the ratio of the dss functional clock / pixel clk. Please refer to section “11.2.4.10.4.2 DISPC Scaling limitations” of AM57x Technical Reference manual for minimum ratio allowed when using the scalar unit.


Running the Display DSS example

Configuring Display:

  • Make sure the LCD panel is connected to the base EVM before running the example binary.
  • Make sure the HDMI is connected to TV from the EVM for HDMI display options.
  • For AM571x IDK EVM, installing a shunt on header J51 to short those pins

CCS connection:

  • Load the generated executable file in CCS
  • Run the application, Select any of the option and load the buffer as suggested.
  • Content will be displayed on the LCD panel or HDMI TV connected to EVM for test options

Note

  • Test Input files for Display Sample application will be in “<pdk>drvvpsdocstest_inputsdss_input_files.rar”

The rar file can be unrar-ed to get the test files using utilities such as https://www.7-zip.org Please download the latest version of 7-zip from this website. The command to unrar is: 7z x {file_to_unrar}

When the test program expects the yuyv422 file, please load display_yuyv422_prog_packed_1920_1080.tigf file and when the test program expects the bgr888 file, please load display_gbr888_prog_packed_1920_1080.tigf file. Each video has 4 frames. Below shows the first frame. If GP EVM is used, only the left upper corner of the video is displayed as it only has an 800x480 LCD.

../_images/488px-Yuyv422.png ../_images/488px-Gbr888.png

The test runs bunch of test cases as shown in the test example menu.

Warning : Due to A15 MMU protection, memory load while CPU is running is not possible. Hence below workaround needs to be done for loading the test files.

  1. Power up the board
  2. Connect to A15 Core
  3. Load both tigf files into memory
  4. Do a CPU reset on A15
  5. Load example code for core type
  6. Run example code

6.26.6.2. Display DSS WB example

Description

The WB pipeline allows the use of the hardware processing available inside the DISPC, such as color space conversion, rescaling, and compositing to perform memory-to-memory transfer with data processing or capturing a displayed frame.

Running Display DSS WB example

The test connection and procedure for this example is very much same as the running the Display DSS example. In this example, the display output that is sent to the output is captured and sent to the WriteBack pipeline.

Loopback (Capture and Display) example

Description

This is the capture and display example that demonstrates the VIP captures functions for the devices. VIP incorporates a multi-channel raw video parser, various video processing blocks, and a flexible Video Port Direct Memory Access (VPDMA)engine to store incoming video in various formats. This example demonstrates the video capture of 720P, YUY422 format from the camera sensor (OV2659 for idkAM57x and OV1063x for evmAM572x) to DPI1 LCD output.

Running Loopback example

  • Make sure OV sensor and LCD Panel is connected to to the board before running the binary.

CCS connection:

  1. Power up the board
  2. Connect to the Core
  3. Run the application, Select any of the option.
  4. Captured Content will be displayed on the LCD panel connected to EVM

Note

The camera driver support is not added for evmAM572x boards (GP AM572x EVM) - and hence all the tests related to camera are skipped for evmAM572x board.


6.26.7. FAQ

How to reduce the VPS test examples build time using makefile?

Please refer to Rebuilding The PDK on how to invoke the build for specific core and specific platform, to save the build time.

How to create a CCS project other than VPS loopback example?

To create a CCS project for other VPS examples, please use the existing text file under PDK_INSTALL_PATHpackagestidrvvpsexamplesccsprojectsam57xxbios as a template:

  • Copy the .txt with desired processor then rename it to a new test project name accord to CCS project create convention, see PDK Example and Test Project Creation
  • Update the linked source files and include paths
  • The common configuration file and build options can be kept
  • Update pre-defined symbol -D<soc_name> to match your SOC, like -DSOC_AM571x, -DSOC_AM572x or -DSOC_AM574x
  • Update the configuration .bld file “-b ${PDK_INSTALL_PATH}/ti/build/<soc>/config_<soc>_<core>.bld” to match your soc
  • In rtsc.setConfiguroOptions, add -DBOARD=<board_name>, which can be idkAM571x, idkAM572x, evmAM572x or idkAM574x
  • Save the file and re-run pdkProjectCreate to create the new added CCS project

Below is example for vps_dssExample_evmAM572x_armExampleProject.txt:

-ccs.linkFile "PDK_INSTALL_PATH/ti/drv/vps/examples/dss/displayDss/src/DisplayDss_main.c"

-ccs.linkFile “PDK_INSTALL_PATH/ti/drv/vps/examples/ccsprojects/common/bios/utils/bspCommonBIOS_a15.cfg”

-ccs.setCompilerOptions “-c -mcpu=cortex-a15 -mtune=cortex-a15 -marm -mfloat-abi=hard -DMAKEFILE_BUILD -DNDEBUG -DTRACE_ENABLE -DASSERT_ENABLE -DVPS_VIP_BUILD -DVPS_VPE_BUILD -DVPS_DSS_BUILD -UVPS_ISS_BUILD -UVPS_SIMCOP_BUILD -UVPS_ISS_ISP_DEF -DVPS_VIP1_BUILD -DVPS_VIP2_BUILD -DVPS_VIP3_BUILD -DVPS_CAPT_BUILD -DVPS_DISP_BUILD -DSOC_AM572x -Dxdc_target_types__=gnu/targets/arm/std.h -Dxdc_target_name__=A15F -g -gstrict-dwarf -gdwarf-3 -Wimplicit -Wall -Wunused -Wunknown-pragmas -ffunction-sections -fdata-sections -MMD -MP -I${PDK_INSTALL_PATH}/ti/drv/vps -I${PDK_INSTALL_PATH}/ti/drv/vps/examples/dss/displayDss/src” -rtsc.enableRtsc

-ccs.setLinkerOptions ” -lrdimon -lgcc -lm -lnosys -nostartfiles -static -Wl,–gc-sections -L$(BIOS_INSTALL_PATH)/packages/gnu/targets/arm/libs/install-native/arm-none-eabi/lib/fpu ” -rtsc.setConfiguroOptions “-b ${PDK_INSTALL_PATH}/ti/build/am572x/config_am572x_a15.bld -DBOARD=evmAM572x”

Can I load any jpeg file into the memory to display through DSS?

The display uses video, not static image as input. There is no JPEG decoder so it will not work.

In DSS example, two input video files are loaded for testing, what is their format and how to play them?

The two files are with .tigf extension. Tigf is a local convention that TI development team followed. The file name (before the extension) shows what you are attempting to decode: e.g., 24 bit RGB or yuyv422 video file with 1920x1080 resolutions. To play them:

  • In Linux, use avplay with syntax: avplay -video_size <wxh> -pixel_format <format> -f rawvideo <video file>, where wxh is 1902x1080 and pixel_format is rgb24 or yuyv422
  • In Windows, use yuv player from: https://sourceforge.net/projects/raw-yuvplayer/

6.27. OSAL

6.27.1. Overview

6.27.1.1. Introduction

The OSAL library provides operating system abstraction layer API sample implementations that are required for processor SDK drivers. Scope of APIs supported in the module is limited to support OS services required for RTOS or bare metal drivers

  • Supported Operating Systems
    • TIRTOS
    • NONOS
  • Supported SOCs
    • Please refer to component release notes

6.27.2. Operating System Extension

6.27.2.1. APIs

Porting of OSAL component will enable extending PDK components to additional OS environment. Reference top level API header file includes:

#include <ti/osal/osal.h>

6.27.3. Application Integration Details

Baremetal or No-OS Use case

Reference library path to be included in application build environment:

<ti/osal/lib/nonos/[soc]/[[cpu]/>

SysBIOS based application

Any RTSC application that needs to use osal library, should have below RTSC configuration lines before any other processor sdk components (e.g., board, gpio, uart etc).

/* set the operating system type,
 * supported types are "tirtos" and "nonos"
 */
var osType           = "tirtos";

/* set the soc type
 * (applicable only when osTYpe
 *  is "nonos" only)
*/
var socType           = "am572x";

/* Setup the OSAL Library */
var Osal = xdc.loadPackage('ti.osal');
Osal.Settings.osType  = osType;
Osal.Settings.socType = socType;

6.27.4. Application

6.27.4.1. Examples

Sysbios Example

This sysbios example OSAL_BasicExample_<board>_<coretype>TestProject tests Hwi, Timer, Delay, Semaphores etc and prints output on UART console.

Introduction

This sysbios based example tests Hwi, Timer, Semaphores etc.

Supported platforms

evmAM335x
evmAM437x
idkAM571x
idkAM574x
evmAM572x
evmK2G
evmK2H
evmOMAPL137
lcdkOMAPL138

Build instructions

Run pdkProjectCreate to create the OSAL_BasicExample_<evm>_<device>TestProject
Load the project on to CCS and build the same.
Build the example
Load the OSAL_BasicExample_<evm>_<device>TestProject
Run the example

Testing the example

The output for each of the tests (Hwi, Timer, Delay, Semaphores etc) can be seen on the UART console. After a successful run, “All tests have PASSED” will be displayed on the screen.

Baremetal Example

Introduction

This baremetal example ‘osal_baremetal_test’ tests Hwi, Timer, Semaphores etc and prints output on UART console.

Supported platforms

evmAM572x
evmAM335x
evmAM437x
evmDRA72x
evmDRA75x
evmDRA78x
iceK2G
idkAM574x
idkAM572x
idkAM571x
idkAM437x

Build instructions

OSAL tests are built using makefiles. The below steps are used to build the baremetal test binaries.

cd pdk_<ver>/packages/
Run pdksetupenv.bat
Run "make osal"
Find the executable at ti/<pdk>/packages/ti/binary/osal_baremetal_test/bin
Load the executable on the board
Before running the executable, please make sure you have the UART connected and notice the test output on the UART console. Osal prints out the results there.

Testing the example

The output for each of the tests (Hwi, Timer, Delay, Semaphores, etc) can be seen on the UART console. After a successful run, “All tests have passed” will be displayed on the screen.

Output

The output of osal example looks like below. The below sample output is from idkAM571x on the UART console.

HWI tests have passed.
TimerTestLog: got 100 ticks from timer id = 1
TimerTestLog: got 100 ticks from timer id = 2
Timer tests have passed.
Running Osal_Delay test:..........
Osal_Delay tests have passed.
Clock tests have passed.
Semaphore tests have passed.
Semaphore Statistics:
PeakSemObjs = 5,
numMaxSemObjs = 100,
numFreeSemObjs = 97
Hwi Statistics:
PeakHwiObjs = 3,
numMaxHwiObjs = 100,
numFreeHwiObjs = 98
Timer Statistics:
PeakTimerObjs = 2,
numMaxTimerObjs = 100,
numFreeTimerObjs = 99
All tests have passed.

6.27.5. Additional References

Operating System Abstraction Layer Library Summary
Component Type Library
Install Package PDK
Install Directory pdk_AMX_<version>\packages\ti\osal
Project Type Eclipse RTSC
Endian Support Little
Linker Path $(TI_PDK_INSTALL_DIR)\packages\ti\osal
Linker Sections .vecs , .switch, .args, .cio
Include Paths $(TI_PDK_INSTALL_DIR)\packages\ti\osal
Reference Guides $(TI_PDK_INSTALL_DIR)\packages\ti\osal\docs\doxygen\html\index.html
Release Notes $(TI_PDK_INSTALL_DIR)\packages\ti\osal\docs\ReleaseNotes_OSAL.pdf

6.28. Profiling

6.28.1. Overview

6.28.1.1. Introduction

The profiling library can be used to profile any of the Platform Development Kit components at the runtime. Feature enables reporting of cpu cycles measurement for PDK driver components in order to analyze and meet constraint requirement for a real time application. Profiling module uses hardware clock of PMU to measure length of each task in processor cycles with minimal overhead. It use standard C programming hooks that may be adapted for any platform and/or processor architecture.

6.28.2. Integration

Baremetal or No-OS Use case

Reference Utils library path to be included in application build environment.

-l <ti/utils/profiling/lib/[cpu]/>

Reference lld library path to be included.(Replace profile suffix library with original one)

-l <ti/drv/uart/lib/[soc]/[cpu]/lld.profiling>

Example:

-l "ti/utils/profiling/lib/armv7/ti.utils.profiling.aa15fg" -l "ti/drv/uart/lib/armv7/ti.drv.uart.profiling.aa15fg>

SysBIOS based application

Refer *.cfg of Uart test application for sample implementation

  1. Load utils package.
var Utils = xdc.loadPackage('ti.utils.profiling');

2. Set the ‘enableProfiling’ attribute to ‘true’ into the .cfg file. This will load library with profiling enabled

var Uart = xdc.loadPackage('ti.drv.uart’);
Uart.Settings.enableProfiling = true;

3. Enable DDR3 memory, if not already enabled in test/example application

Program.sectMap[".fardata:benchmarking"] = "DDR3";

4. Add following line in .cfg if it does not exist already. Enable the Task hooks for Task switches.

var Task = xdc.useModule('ti.sysbios.knl.Task');

Task.addHookSet({
registerFxn: '&TaskRegisterId',
switchFxn: '&mySwitch',
});

Additional compiler flags

  1. For gcc compiler add
-gdwarf-3 -finstrument-functions
  1. For TI compiler add
--entry_parm=address --exit_hook=ti_utils_exit --exit_parm=address --entry_hook=ti_utils_entry

Reference: *project.txt inside UART test application

6.28.3. Rebuild the project

Profiling Processing

All LLD Test/DMATest projects located under “LLD/test/” has profiling configuration enabled by default.

Load compiled program onto desired target and platform. Run program to a desired logical point where profiling data needs to be collected

1. While program is at the break, open the Memory Browser (View > Memory Browser).

2. Save a memory snapshot by clicking “Save”, setting the start address to “elemlog” and length to “log_idx*4”. (It is preferred to save it into ti .dat format.)


Profiling Post-processing

Host Environment:Windows or Ubuntu Tools dependencies:

Tools Download
python 2.7 https://www.python.org/downloads/
pyelftools https://github.com/eliben/pyelftools
tabulate https://pypi.python.org/pypi/tabulate
XlsxWriter https://pypi.python.org/pypi/XlsxWriter#downloads

(Follow the standard instruction for installing the tools from their websites.)

Running the script

Open a cmd/terminal & set to the directory of the “decodeProfileDump.py” Python script (typically under utils/profiling/scripts)

python decodeProfileDump.py -flags [log 1] [executable 1]

Example:

python decodeProfileDump.py -v uart.dat UART_BasicExample_k2h_armTestproject.out

Optional flags

Flags Response
-v Display verbose output
–t Breakdown function totals by their reference sites
–x Print the tabulated results into a report.xlsx Excel file
-csv Print the tabulated results into a report.csv file
-off N Manual instrumentation offset of N cycles, subtracted from each function.

(The instrumentation program already generates an offset from itself that is subtracted from the function times. Use this flag only if there is an additional offset you would like to subtract.)

Report Fields

Term Meaning
Function Name of instrumented function
Referenced_By Call site of instrumented function
Total_Cycles Inclusive/Exclusive processor cycles elapsed for instrumented function
Average_Cycles Processor cycles elapsed for instrumented function per reference
Total_Calls Number of times instrumented function is called
Average_Calls Number of times instrumented function is called per reference
Iterations Number of times instrumented function was referenced

(inclusive(inc): including the cycles of its child functions within, exclusive(exc): excluding the cycles of its child functions.)

Note

Remaining functions on the stack at last timestamp will be considered closed.

BIOS functions are not accounted by instrumentation and will not appear in the report.

Functions which are optimized out will not appear in the report eg. empty/single-line functions, ti_sysbios_* functions etc.