PSE Configuration (Ubuntu)

Applicable to: K400 series systems

Installation (Intel IoT)

Ubuntu Desktop 20.04 and 22.04 for Intel IoT platforms are versions of Ubuntu that are validated to run a 5.13-intel and 5.15-intel kernel version. This version of Ubuntu is available from Canonical at https://ubuntu.com/download/iot/intel-iotg, and can be installed like any other Ubuntu release.

IMPORTANT In some releases of Ubuntu, the 'pinctrl_elkhartlake' driver will timeout 
during startup and crash during shutdown. You can utilize the method below to 
address the issue, by disabling this driver module.

One method is to add "modprobe.blacklist=pinctrl_elkhartlake" to the kernel command 
line.

PSE Driver Installation

Several system hardware interfaces, including CAN, DIO, Serial/COM and ignition sensing are managed through the system’s Programmable Services Engine (PSE).

The Elkhart Lake PSE can be managed over ISHTP/HECI from the host processor: This driver creates and manages a pse character device, which allows userspace applications to read and write data over the underlying ISHTP bus driver.

You can download the driver files and installation bundle here: PSE HECI Driver v1.0.0.

Or download and extract them from the command line:

$ wget https://static.onlogic.com/resources/firmware/utilities/pse_heci_v100.zip && unzip pse_heci_v100.zip -d pse_heci && cd pse_heci
NOTE This driver was written for the 5.13.0-intel kernel. Running it against any other kernel version may require modification. At a minimum, the system requires an ISHTP bus device with UUID bb579a2e-cc54-4450-b1d0-5e7520dcad25, and the bundled additional source headers (intel-ish-hid-5.13) will need to be updated.

Quickstart

To build and install the pse kernel module automatically, simply run:

This will check if the pre-compiled kernel modules are compatible with your system, and either install them or compile new ones in-place. If all goes well, you can move on to Using the PSE.

Building

It is also possible to manually build and install the PSE kernel module, which may be required if you intend to run a signed kernel.

Build Preparation

Install the prerequisites for building kernel modules:

Download the kernel headers for the current kernel:

Build

You should now be able to build with:

This will generate the kernel modules files, which can be loaded and checked with:

Install

Permanently installing the PSE driver can be done by copying it to your modules directory:

After this, the PSE module should be loaded and ready for use on each boot. You can confirm this with:

Using the PSE

The programmable services engine consumes commands in the form of packed header and body data structures. The complexity of these structures can be completely ignored by using the pre-compiled command-line application. See the Hardware Control Application (HWC) download within the system product documentation.

However, for tight application integration, it is possible to interface with the PSE directly from your software stack by reading and writing to the PSE character file (/dev/pse). A complete example that establishes a connection to the PSE and reads the firmware version information is included in the examples directory, and can be compiled with:

All source code referenced in the instructions below is included in full context in the examples directory. Additional example code is provided for using the CAN and DIO peripherals, as well as sample code for configuring the system’s automotive features. You can build all targets with:

1. Establish Connection

Before communication with the PSE can begin, the host client must establish a connection with the firmware client. This is performed by sending the ‘client connection’ IOCTL to the device file:

Once the connection has been established and returned, it is possible to send commands to the PSE.

2. Send a Command

Commands sent to the programmable services engine can either be header-only ‘short’ commands, or complete header + body ‘long’ commands.

The header portion of the command is as 48-bit wide structure that is transmitted as raw data to the PSE:

The command header can be easily described as a packed struct in C:

The possible valid system commands are enumerated by the heci_command_id_t, and include:

Command
Value
Description

System Info

0x01

Report the system firmware version number

Digital IO

0x02

Set and read the system’s digital IO and LEDs

UART

0x03

Send data over an attached UART. Allows control of automotive features

CAN Bus

0x04

Send and receive CAN messages

PWM

0x05

Manage the Pulse Width Modulation of a DIO configured as PWM

I2C

0x06

Send/receive I2C data (not recommended for end-user configuration)

QEP

0x07

Configure a group of DIOs set as a Quadrature Encoder Peripheral

The argument packing depends on this command, and is described by the *_command_t structures.

UART, I2C, PWM, and QEP all use a generic ‘operation + device’ scheme, while DIO and CAN have separate formats:

The ‘body’ portion of each command is described by another structure:

The actual data format depends on the command sent; the can_send example function in examples/can.c shows one method for populating message data.

Once a message’s header and optional body portions are prepared, sending the command is as simple as writing to the open PSE device:

3. Read the Response

Any message sent to the PSE will receive a response from the embedded controller. The response message format is identical to the transmit format, and will always include the status of the last command received.

Some commands (like reading a CAN message), will result in additional data being returned, as indicated by the has_next flag. Application code may check this flag to determine if it should continue reading data:

4. Minimal Example

In the provided sample code, the files examples/pse.c and examples/pse.h provide some helpful abstraction to simplify this process. For instance, reading the PSE firmware version can be performed with the following code:

Last updated