HDMI

Overview

HDMI

High-definition multimedia interface (HDMI) is an interface for transmitting audio and video data from a source device, such as a DVD player or set-top box (STB), to a sink device, such as a TV or display. HDMI usually has a source and a sink. The HDMI APIs provide a set of common functions for HDMI transmission, including:

  • Opening and closing an HDMI controller
  • Starting and stopping HDMI transmission
  • Setting audio, video, and High Dynamic Range (HDR) attributes, color depth, and AV mute
  • Reading the raw Extended Display Identification Data (EDID) from a sink
  • Registering and unregistering a callback for HDMI hot plug detect (HPD)

Basic Concepts

HDMI is an audio and video transmission protocol released by Hitachi, Panasonic, Philips, Silicon Image, Sony, Thomson, and Toshiba. The transmission process complies with the Transition-minimized Differential Signaling (TMDS).

  • TMDS is used to transmit audio, video, and various auxiliary data.
  • Display data channel (DDC) allows the TX and RX ends to obtain the transmitting and receiving capabilities. However, HDMI only needs to unidirectionally obtain the capabilities of the RX end (display).
  • Consumer Electronics Control (CEC) enables interaction between the HDMI TX and RX devices.
  • Fixed rate link (FRL) allows the maximum TMDS bandwidth to be increased from 18 Gbit/s to 48 Gbit/s.
  • High-bandwidth Digital Content Protection (HDCP) prevents copying of digital audio and video content being transmitted across devices.
  • EDID, usually stored in the display firmware, provides the vendor information, EDID version, maximum image size, color settings, vendor pre-settings, frequency range limit, display name, and serial number.

Working Principles

The HDMI source provides +5 V and GND for DDC and CEC communication. Through the DDC, the source obtains the sink parameters, such as the RX capabilities. The CEC provides an optional channel to synchronize control signals between the source and sink for better user experience. There are four TMDS channels between the HDMI source and sink. The TMDS clock channel provides clock signals for TMDS, and the other three channels transmit audio, video, and auxiliary data. HDP is the hot plug detect port. When the sink is connected, the source responds by using an interrupt service routine (ISR).

The figure below shows the HDMI physical connection.

Figure 1 HDMI physical connection

Constraints

Currently, the HDMI module supports only the kernels (LiteOS) of mini and small systems.

Development Guidelines

When to Use

HDMI features high transmission rate, wide transmission bandwidth, high compatibility, and can transmit uncompressed audio and video signals. Compared with the traditional full analog interface, HDMI simplifies connection between devices and provides HDMI-specific intelligent features, which are ideal for high-quality audio and video transmission of small-sized devices.

Available APIs

Table 1 HDMI driver APIs

API Description
HdmiOpen Opens an HDMI controller.
HdmiClose Closes an HDMI controller.
HdmiStart Starts HDMI transmission.
HdmiStop Stops HDMI transmission.
HdmiAvmuteSet Sets the AV mute feature.
HdmiDeepColorSet Sets the color depth.
HdmiDeepColorGet Obtains the color depth.
HdmiSetVideoAttribute Sets video attributes.
HdmiSetAudioAttribute Sets audio attributes.
HdmiSetHdrAttribute Sets HDR attributes.
HdmiReadSinkEdid Reads the raw EDID from a sink.
HdmiRegisterHpdCallbackFunc Registers a callback for HDMI HPD.
HdmiUnregisterHpdCallbackFunc Unregisters a callback for HDMI HPD.

How to Develop

The figure below illustrates the general HDMI development process.

Figure 2 Using HDMI driver APIs

Opening an HDMI Controller

Before HDMI communication, call HdmiOpen() to open an HDMI controller.

DevHandle HdmiOpen(int16_t number);

Table 2 Description of HdmiOpen

Parameter Description
number HDMI controller ID.
Return Value Description
NULL The operation failed.
Controller handle Handle of the opened HDMI controller.

For example, open controller 0 of the two HDMI controllers (numbered 0 and 1) in the system:

DevHandle hdmiHandle = NULL; /* HDMI controller handle /

/* Open HDMI controller 0. */
hdmiHandle = HdmiOpen(0);
if (hdmiHandle == NULL) {
    HDF_LOGE("HdmiOpen: failed\n");
    return;
}

Registering a Callback for HPD

int32_t HdmiRegisterHpdCallbackFunc(DevHandle handle, struct HdmiHpdCallbackInfo *callback);

Table 3 Description of HdmiRegisterHpdCallbackFunc

Parameter Description
handle HDMI controller handle.
callback Pointer to the callback to be invoked to return the HPD result.
Return Value Description
0 The operation is successful.
Negative value The operation failed.

The following is an example of registering a callback for HPD:

/* Definition of the callback for HPD */
static void HdmiHpdHandle(void *data, bool hpd)
{
    if (data == NULL) {
        HDF_LOGE("priv data is NULL");
        return;
    }
    if (hpd == true) {
        HDF_LOGD("HdmiHpdHandle: hot plug");
        /* Add related processing if required. */
    } else {
        HDF_LOGD("HdmiHpdHandle: hot unplug");
        /* Add related processing if required. */
    }
}

/* Example of registering a callback for HPD */
···
struct HdmiHpdCallbackInfo info = {0};
info.data = handle;
info.callbackFunc = HdmiHpdHandle;
ret = HdmiRegisterHpdCallbackFunc(hdmiHandle, info);
if (ret != 0) {
    HDF_LOGE("HdmiRegisterHpdCallbackFunc: Register failed.");
}
···

Reading the Raw EDID

int32_t HdmiReadSinkEdid(DevHandle handle, uint8_t *buffer, uint32_t len);

Table 4 Description of HdmiReadSinkEdid

Parameter Description
handle HDMI controller handle.
buffer Pointer to the data buffer.
len Data length.
Return Value Description
Positive integer Raw EDID read.
Negative number or 0 Failed to read the EDID.

The following is an example of reading the raw EDID from a sink:

int32_t len;
uint8_t edid[HDMI_EDID_MAX_LEN] = {0};

len = HdmiReadSinkEdid(hdmiHandle, edid, HDMI_EDID_MAX_LEN);
if (len <= 0) {
    HDF_LOGE("%s: HdmiReadSinkEdid failed len = %d.", __func__, len);
}

Setting Audio Attributes

int32_t HdmiSetAudioAttribute(DevHandle handle, struct HdmiAudioAttr *attr);

Table 5 Description of HdmiSetAudioAttribute

Parameter Description
handle HDMI controller handle.
attr Pointer to the audio attributes.
Return Value Description
0 The operation is successful.
Negative value The operation failed.

The following is an example of setting audio attributes:

struct HdmiAudioAttr audioAttr = {0};
int32_t ret;

audioAttr.codingType = HDMI_AUDIO_CODING_TYPE_MP3;
audioAttr.ifType = HDMI_AUDIO_IF_TYPE_I2S;
audioAttr.bitDepth = HDMI_ADIO_BIT_DEPTH_16;
audioAttr.sampleRate = HDMI_SAMPLE_RATE_8K;
audioAttr.channels = HDMI_AUDIO_FORMAT_CHANNEL_3;
ret = HdmiSetAudioAttribute(handle, &audioAttr);
if (ret != 0) {
    HDF_LOGE("HdmiSetAudioAttribute failed.");
}

Setting Video Attributes

int32_t HdmiSetVideoAttribute(DevHandle handle, struct HdmiVideoAttr *attr);

Table 6 Description of HdmiSetVideoAttribute

Parameter Description
handle HDMI controller handle.
attr Pointer to the video attributes.
Return Value Description
0 The operation is successful.
Negative value The operation failed.

The following is an example of setting video attributes:

struct HdmiVideoAttr videoAttr = {0};
int32_t ret;

videoAttr.colorSpace = HDMI_COLOR_SPACE_YCBCR444;
videoAttr.colorimetry = HDMI_COLORIMETRY_EXTENDED;
videoAttr.extColorimetry = HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM;
videoAttr.quantization = HDMI_QUANTIZATION_RANGE_FULL;
ret = HdmiSetVideoAttribute(handle, &videoAttr);
if (ret != 0) {
    HDF_LOGE("HdmiSetVideoAttribute failed.");
}

Setting HDR Attributes

int32_t HdmiSetHdrAttribute(DevHandle handle, struct HdmiHdrAttr *attr);

Table 7 Description of HdmiSetHdrAttribute

Parameter Description
handle HDMI controller handle.
attr Pointer to the HDR attributes
Return Value Description
0 The operation is successful.
Negative value The operation failed.

The following is an example of setting HDR attributes:

struct HdmiHdrAttr hdrAttr = {0};
int32_t ret;

hdrAttr.mode = HDMI_HDR_MODE_CEA_861_3;
hdrAttr.userMode = HDMI_HDR_USERMODE_DOLBY;
hdrAttr.eotfType = HDMI_EOTF_SMPTE_ST_2048;
hdrAttr.metadataType = HDMI_DRM_STATIC_METADATA_TYPE_1;
hdrAttr.colorimetry = HDMI_HDR_EXTENDED_COLORIMETRY_XV_YCC_709;
ret = HdmiSetHdrAttribute(handle, &hdrAttr);
if (ret != 0) {
    HDF_LOGE("HdmiSetHdrAttribute failed.");
}

Setting HDMI AV Mute

int32_t HdmiAvmuteSet(DevHandle handle, bool enable);

Table 8 Description of HdmiAvmuteSet

Parameter Description
handle HDMI controller handle.
enable Whether to enable the AV mute feature.
Return Value Description
0 The operation is successful.
Negative value The operation failed.

The following is an example of setting AV mute:

int32_t ret;

ret = HdmiAvmuteSet(hdmiHandle, true);
if (ret != 0) {
    HDF_LOGE("HdmiAvmuteSet failed.");
}

Setting the Color Depth

int32_t HdmiDeepColorSet(DevHandle handle, enum HdmiDeepColor color);

Table 9 Description of HdmiDeepColorSet

Parameter Description
handle HDMI controller handle.
color Color depth to set.
Return Value Description
0 The operation is successful.
Negative value The operation failed.

The following is an example of setting the color depth:

int32_t ret;

ret = HdmiDeepColorSet(handle, HDMI_DEEP_COLOR_48BITS);
if (ret != 0) {
    HDF_LOGE("HdmiDeepColorSet failed.");
}

Obtaining the Color Depth

int32_t HdmiDeepColorGet(DevHandle handle, enum HdmiDeepColor *color);

Table 10 Description of HdmiDeepColorGet

Parameter Description
handle HDMI controller handle.
color Pointer to the color depth.
Return Value Description
0 The operation is successful.
Negative value The operation failed.

The following is an example of obtaining the color depth:

enum HdmiDeepColor color;
int32_t ret;

ret = HdmiDeepColorGet(handle, &color);
if (ret != 0) {
    HDF_LOGE("HdmiDeepColorGet failed.");
}

Starting HDMI Transmission

int32_t HdmiStart(DevHandle handle);

Table 11 Description of HdmiStart

Parameter Description
handle HDMI controller handle.
Return Value Description
0 The operation is successful.
Negative value The operation failed.

The following is an example of starting HDMI transmission:

int32_t ret;

ret = HdmiStart(hdmiHandle);
if (ret != 0) {
    HDF_LOGE("Failed to start transmission.");
}

Stopping HDMI Transmission

int32_t HdmiStop(DevHandle handle);

Table 12 Description of HdmiStop

Parameter Description
handle HDMI controller handle.
Return Value Description
0 The operation is successful.
Negative value The operation failed.

The following is an example of stopping HDMI transmission:

int32_t ret;

ret = HdmiStop(hdmiHandle);
if (ret != 0) {
    HDF_LOGE("Failed to stop transmission.");
}

Unregistering the Callback for HPD

int32_t HdmiUnregisterHpdCallbackFunc(DevHandle handle);

Table 13 Description of HdmiUnregisterHpdCallbackFunc

Parameter Description
handle HDMI controller handle.
Return Value Description
0 The operation is successful.
Negative value The operation failed.

The following is an example of unregistering the callback for HPD:

int32_t ret;

ret = HdmiUnregisterHpdCallbackFunc(hdmiHandle);
if (ret != 0) {
    HDF_LOGE("unregister failed.");
}

Closing an HDMI Controller

void HdmiClose(DevHandle handle);

Table 14 Description of HdmiClose

Parameter Description
handle HDMI controller handle.

The following is an example of closing an HDMI controller:

HdmiClose(hdmiHandle);

Example

This following example shows how to use HDMI APIs to manage an HDMI device on a Hi3516D V300 development board.

A virtual driver is used in this example. The hardware information is as follows:

  • SoC: Hi3516D V300

  • HDMI controller: HDMI controller 0

The sample code is as follows:

#include "hdmi_if.h"          /* Header file for HDMI standard APIs */
#include "hdf_log.h"         /* Header file for log APIs */
#include "osal_time.h"       /* Header file for delay and sleep APIs */

/* Callback for hog plug detect */
static void HdmiHpdHandle(void *data, bool hpd)
{
    if (data == NULL) {
    HDF_LOGE("priv data is NULL");
    return;
    }

    if (hpd == true) {
        HDF_LOGD("HdmiHpdHandle: hot plug");
        /* Add related processing if required. */
    } else {
        HDF_LOGD("HdmiHpdHandle: hot unplug");
        /* Add related processing if required. */
    }
}

/* Set HDMI attributes. */
static int32_t TestHdmiSetAttr(DevHandle handle)
{
    enum HdmiDeepColor color;
    struct HdmiVideoAttr videoAttr = {0};
    struct HdmiAudioAttr audioAttr = {0};
    struct HdmiHdrAttr hdrAttr = {0};
    int32_t ret;

    ret = HdmiDeepColorSet(handle, HDMI_DEEP_COLOR_48BITS);
    
    if (ret != 0) {
        HDF_LOGE("HdmiDeepColorSet failed.");
        return ret;
    }
    ret = HdmiDeepColorGet(handle, &color);
    if (ret != 0) {
        HDF_LOGE("HdmiDeepColorGet failed.");
        return ret;
    }
    HDF_LOGE("HdmiDeepColorGet successful, color = %d.", color);
    videoAttr.colorSpace = HDMI_COLOR_SPACE_YCBCR444;
    videoAttr.colorimetry = HDMI_COLORIMETRY_EXTENDED;
    videoAttr.extColorimetry = HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM;
    videoAttr.quantization = HDMI_QUANTIZATION_RANGE_FULL;
    ret = HdmiSetVideoAttribute(handle, &videoAttr);
    if (ret != 0) {
        HDF_LOGE("HdmiSetVideoAttribute failed.");
        return ret;
    }
    audioAttr.codingType = HDMI_AUDIO_CODING_TYPE_MP3;
    audioAttr.ifType = HDMI_AUDIO_IF_TYPE_I2S;
    audioAttr.bitDepth = HDMI_ADIO_BIT_DEPTH_16;
    audioAttr.sampleRate = HDMI_SAMPLE_RATE_8K;
    audioAttr.channels = HDMI_AUDIO_FORMAT_CHANNEL_3;
    ret = HdmiSetAudioAttribute(handle, &audioAttr);
    if (ret != 0) {
        HDF_LOGE("HdmiSetAudioAttribute failed.");
        return ret;
    }
    hdrAttr.mode = HDMI_HDR_MODE_CEA_861_3;
    hdrAttr.userMode = HDMI_HDR_USERMODE_DOLBY;
    hdrAttr.eotfType = HDMI_EOTF_SMPTE_ST_2048;
    hdrAttr.metadataType = HDMI_DRM_STATIC_METADATA_TYPE_1;
    hdrAttr.colorimetry = HDMI_HDR_EXTENDED_COLORIMETRY_XV_YCC_709;
    ret = HdmiSetHdrAttribute(handle, &hdrAttr);
    if (ret != 0) {
        HDF_LOGE("HdmiSetHdrAttribute failed.");
        return ret;
    }

    return 0;
}

/* Main entry of HDMI routines */
static int32_t TestCaseHdmi(void)
{
    DevHandle handle = NULL;
    int32_t ret;

    struct HdmiHpdCallbackInfo info = {0};
    uint8_t data[128] = {0};

    HDF_LOGD("HdmiAdapterInit: successful.");
    handle = HdmiOpen(0);
    if (handle == NULL) {
        HDF_LOGE("HdmiOpen failed.");
        return ret;
    }
    info.data = handle;
    info.callbackFunc = HdmiHpdHandle;
    ret = HdmiRegisterHpdCallbackFunc(handle, &info);
    if (ret != 0) {
        HDF_LOGE("HdmiRegisterHpdCallbackFunc failed.");
        return ret;
    }

    ret = HdmiReadSinkEdid(handle, data, 128);
    if (ret <= 0) {
        HDF_LOGE("HdmiReadSinkEdid failed.");
        return ret;
    }
    HDF_LOGE("HdmiReadSinkEdid successful, data[6] = %d, data[8] = %d.", data[6], data[8]);

    ret = TestHdmiSetAttr(handle);
    if (ret != 0) {
        HDF_LOGE("TestHdmiSetAttr failed.");
        return ret;
    }

    ret = HdmiStart(handle);
    if (ret != 0) {
        HDF_LOGE("HdmiStart failed.");
        return ret;
    }

    OsalMSleep(1000);

    ret = HdmiStop(handle);
    if (ret != 0) {
        HDF_LOGE("HdmiStop failed.");
        return ret;
    }

    ret = HdmiUnregisterHpdCallbackFunc(handle);
    if (ret != 0) {
        HDF_LOGE("HdmiUnregisterHpdCallbackFunc failed.");
        return ret;
    }
    HdmiClose(handle);
    return 0;
}