Skip to main content

2. Peripherals and Interfaces

2.1 Hardware resource diagram

No.InterfaceNo.Interface
1RTC battery connector10Power Delivery over Type-C
2Micro USB (UART debug)11PWR button
3TurboX C6490P SOM12EDL button
43.5mm headphone jack13Camera connector 2
5USB Type-C with DP (USB 3.1)14Camera connector 1
6USB Type-A (USB 2.0)15Wi-Fi/BT module
72 x USB Type-A (USB 3.0)16Fan connector
81000M Ethernet1740-pin LS connector
9HDMI OUT18M.2 Key M connector

2.2 40-pin LS connector

2.2.1 GPIO

RUBIK Pi 3 is compatible with WiringRP (based on the high-performance GPIO programming library WiringPi). It is recommended to use WiringRP for controlling and programming GPIOs. For more details about WiringRP, visit https://github.com/rubikpi-ai/WiringRP.

2.2.1.1 Pinout

The figure below shows the default functions of the RUBIK Pi 3 40-pin LS connector, most of which are compatible with the default functions of the Raspberry Pi 40-pin connector.

The following table lists all functions of the 40-pin LS connector. Blue bold functions are default functions.

2.2.1.2 Control GPIOs using shell commands

Run the following commands on RUBIK Pi 3 to control GPIOs.

  • Using WiringRP commands:

    • View the GPIO status

      gpio readall

    • Set the GPIO mode

      gpio mode 15 in             # Set pin 15 to input mode
      gpio pins # Check the mode
      gpio mode 15 out # Set pin 15 to output mode
      gpio pins # Check the mode
    • Set the pin level

      gpio write 15 1             # Set pin 15 to high level
      gpio read 15 # Check the pin level
      gpio write 15 0 # Set pin 15 to low level
      gpio read 15 # Check the pin level
  • Operate nodes under /sys/class/gpio

    The table below shows the GPIO subsystem numbering.

    • Go to the /sys/class/gpio directory:

      cd /sys/class/gpio
    • Export the GPIO to be controlled. For example, pin 13 GPIO_24:

      echo 559 > export
    • Go to the gpio559 directory to set GPIO attributes:

      cd gpio559  
      ls

    The attributes are described as follows:

    • direction:
      • Input: in
      • Output: out
    • value:
      • Low level: 0
      • High level: 1
    • edge (interrupt edge):
      • Rising edge trigger: rising
      • Falling edge trigger: falling
      • Both-edge trigger: both
      • Disabling interrupts: none

    For example, set pin 13 to output a high level:

    echo out > direction  
    echo 1 > value

    Cancel the export of pin 13 to user space:

    echo 559 > unexport

2.2.1.3 Control GPIOs using WiringRP (C)

The WiringRP library provides a set of API functions that enable control with minimal logic.

  • The following code snippet sets pin 13 as output, pin 15 as input, and loops to check the level status of pin 15.

    #include <stdio.h>
    #include <wiringPi.h>

    int main (void)
    {
    wiringPiSetup () ;
    pinMode (13, OUTPUT) ;
    pinMode (15, INPUT) ;

    for (;;)
    {
    digitalWrite (13, HIGH) ; // On
    printf("%d\n", digitalRead (15)); // On
    delay (1000) ; // mS
    digitalWrite (13, LOW) ; // Off
    printf("%d\n", digitalRead (15)); // On
    delay (1900) ;
    }

    return 0 ;
    }
  • Compile programs:

    • Compile on RUBIK Pi 3

      adb push gpio.c /opt
      adb shell
      cd /opt
      gcc gpio.c -o gpio -lwiringPi
  • Short pin 13 and pin 15 with a Dupont wire, as shown in the following figure, to test the GPIO level control and read the level.

    Run the following commands:

    cd /opt
    ./gpio

    The program execution result is as follows:

2.2.1.4 Control GPIOs using WiringRP-Python

The WiringRP library provides a set of API functions that enable control with minimal logic.

  • The following code snippet is an example of controlling GPIOs using the WiringRP library: set pin 13 as output, pin 15 as input, and loops to check the level status of pin 15.

    import wiringpi
    import time

    wiringpi.wiringPiSetup()
    wiringpi.pinMode(13, 1)
    wiringpi.pinMode(15, 0)
    wiringpi.digitalRead(15)

    while True:
    wiringpi.digitalWrite(13,1)
    pin_level = wiringpi.digitalRead(15)
    print(f"in_gpio level: {pin_level}")

    time.sleep(1)

    wiringpi.digitalWrite(13,0)
    pin_level = wiringpi.digitalRead(15)
    print(f"in_gpio level: {pin_level}")

    time.sleep(1)
  • Transfer gpio.py to RUBIK Pi 3. For example, use the ADB method.

    adb push gpio.py /opt
  • Short pin 13 and pin 15 with a Dupont wire, as shown in the following figure, to test the GPIO level control and read the level.

    Run the following commands:

    cd /opt
    python3 gpio.py

    The program execution result is as follows:

2.2.1.5 Control GPIOs using Python programs

  • GPIOs can be controlled by using python-periphery. Run the following command to install python-periphery on RUBIK Pi 3:

    pip3 install python-periphery
  • The following code snippet uses python-periphery to operate GPIOs: set pin 13 as output, pin 15 as input, and loop to check the level status of pin 15.

    from periphery import GPIO
    import time

    out_gpio = GPIO(559, "out")
    in_gpio = GPIO(560, "in")

    try:
    while True:
    try:
    out_gpio.write(True)
    pin_level = in_gpio.read()
    print(f"in_gpio level: {pin_level}")

    out_gpio.write(False)
    pin_level = in_gpio.read()
    print(f"in_gpio level: {pin_level}")

    time.sleep(1)

    except KeyboardInterrupt:
    out_gpio.write(False)
    break

    except IOError:
    print("Error")

    finally:
    out_gpio.close()
    in_gpio.close()
  • Transfer gpio.py to RUBIK Pi 3. For example, use the ADB method.

    adb push gpio.py /opt
  • Short pin 13 and pin 15 with a Dupont wire, as shown in the following figure, to test the GPIO level control and read the level.

    Run the following commands:

    cd /opt
    python3 gpio.py

    The program execution result is as follows:

2.2.1.6 Control GPIOs using C programs

  • The following code snippet sets pin 13 as output, pin 15 as input, and loops to check the level status of pin 15.

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>

    int out_gpio = 559;
    int in_gpio = 560;

    int main() {
    char export_path[50] = {};
    char export_command[100] = {};
    snprintf(export_path, sizeof(export_path), "/sys/class/gpio/export");
    snprintf(export_command, sizeof(export_command), "echo %d > %s ", out_gpio, export_path);
    system(export_command);
    snprintf(export_command, sizeof(export_command), "echo %d > %s ", in_gpio, export_path);
    system(export_command);

    char direction_path[50] = {};
    snprintf(direction_path, sizeof(direction_path), "/sys/class/gpio/gpio%d/direction", out_gpio);
    FILE *direction_file = fopen(direction_path, "w");
    if (direction_file == NULL) {
    perror("Failed to open GPIO direction file");
    return -1;
    }
    fprintf(direction_file, "out");
    fclose(direction_file);

    snprintf(direction_path, sizeof(direction_path), "/sys/class/gpio/gpio%d/direction", in_gpio);
    direction_file = fopen(direction_path, "w");
    if (direction_file == NULL) {
    perror("Failed to open GPIO direction file");
    return -1;
    }
    fprintf(direction_file, "in");
    fclose(direction_file);

    char value_in_path[50] = {};
    char value_out_path[50] = {};
    char cat_command[100] = {};
    snprintf(value_out_path, sizeof(value_out_path), "/sys/class/gpio/gpio%d/value", out_gpio);
    snprintf(value_in_path, sizeof(value_in_path), "/sys/class/gpio/gpio%d/value", in_gpio);
    snprintf(cat_command, sizeof(cat_command), "cat %s", value_in_path);

    FILE *value_out_file = fopen(value_out_path, "w");
    if (value_out_file == NULL) {
    perror("Failed to open GPIO value file");
    return -1;
    }

    for (int i = 0; i < 5; i++) {
    fprintf(value_out_file, "1");
    fflush(value_out_file);

    system(cat_command);
    sleep(1);

    fprintf(value_out_file, "0");
    fflush(value_out_file);

    system(cat_command);
    sleep(1);
    }

    fclose(value_out_file);

    char unexport_path[50] = {};
    char unexport_command[100] = {};
    snprintf(unexport_path, sizeof(unexport_path), "/sys/class/gpio/unexport");
    snprintf(unexport_command, sizeof(unexport_command), "echo %d > %s ", out_gpio, unexport_path);
    system(unexport_command);
    snprintf(unexport_command, sizeof(unexport_command), "echo %d > %s ", in_gpio, unexport_path);
    system(unexport_command);

    return 0;
    }
  • Compile programs

    • Cross-compile the program. For details, refer to 1.11.3. Use the cross-compilation tools.

      aarch64-qcom-linux-gcc gpio.c -o gpio --sysroot=/home/zhy/qcom_sdk_meta/sysroots/armv8-2a-qcom-linux/
    • Compile on RUBIK Pi 3

      adb push gpio.c /opt
      adb shell
      cd /opt
      gcc gpio.c -o gpio

      If you use cross-compilation, transfer gpio to RUBIK Pi 3. For example, use the ADB method.

      adb push gpio /opt
  • Short pin 13 and pin 15 with a Dupont wire, as shown in the following figure, to test the GPIO level control and read the level.

    Run the following commands:

    cd /opt
    ./gpio

    The program execution result is as follows:

2.2.2 I2C

RUBIK Pi 3 is compatible with WiringRP (based on the high-performance GPIO programming library WiringPi). It is recommended to use WiringRP for controlling and programming I2C. For more details about WiringRP, visit https://github.com/rubikpi-ai/WiringRP.

2.2.2.1 Pinout

The figure below shows the default functions of the RUBIK Pi 3 40-pin LS connector, most of which are compatible with the default functions of the Raspberry Pi 40-pin connector.

note

Pin 3 and pin 5 are set to I2C1 by default.

The following table lists all functions of the 40-pin LS connector. Blue bold functions are default functions.

2.2.2.2 I2C communication using shell commands

Run the following commands on RUBIK Pi 3 to control the I2C bus.

  • Use the WiringRP related command

    ./gpio -x ads1115:100:10 aread 100     #Read the analog signal value of the ADS1115 device via the I2C bus.
  • Use the i2cdetect tool

    • View devices connected to the I2C1 interface:

      i2cdetect -a -y -r 1
    • Read all registers of the device whose address is 0x38:

      i2cdump -f -y 1 0x38
    • Write 0xaa to register 0x01 of the device whose address is 0x38:

      i2cset -f -y 1 0x38 0x01 0xaa
    • Read the value at register 0x01 of the device whose address is 0x38:

      i2cget -f -y 1 0x38 0x01

2.2.2.3 I2C communication using WiringRP (C)

The WiringRP library provides a set of API functions that enable control with minimal logic.

  • The following code snippet uses the I2C1 bus to communicate with a device whose address is 0x38: write 0xaa to the 0x01 address of the device.

    #include <wiringPi.h>
    #include <stdio.h>
    #include <stdlib.h>

    #define I2C_ADDRESS 0x38

    int main(void) {
    int fd;

    if (wiringPiSetup() == -1) {
    exit(1);
    }

    fd = wiringPiI2CSetup(I2C_ADDRESS);
    if (fd == -1) {
    exit(1);
    }

    unsigned char data[2];
    if (read(fd, data, 2) != 2) {
    exit(1);
    }

    wiringPiI2CWriteReg8 (fd, 0x01, 0xaa) ;

    close(fd);
    return 0;

  • Compile programs

    • Compile on RUBIK Pi 3

      adb push gpio.c /opt
      adb shell
      cd /opt
      gcc i2c.c -o i2c -lwiringPi
  • Connect pin 3 and pin 5 to the I2C sensor and test the I2C communication as shown in the following figure.

    Run the following commands:

    cd /opt
    ./i2c

2.2.2.4 I2C communication using WiringRP-Python

The WiringRP library provides a set of API functions that enable control with minimal logic.

  • The following code snippet uses the I2C1 bus to communicate with a device whose address is 0x38: write 0xaa to the 0x01 address of the device.

    import wiringpi as wpi

    wpi.wiringPiSetup()
    fd=wpi.wiringPiI2CSetup(0x38, 1)
    wpi.wiringPiI2CWriteReg8 (fd, 0x01, 0xaa)

  • Transfer i2c.py to RUBIK Pi 3. For example, use the ADB method.

    adb push i2c.py /opt
  • Connect pin 3 and pin 5 to the I2C sensor and test the I2C communication as shown in the following figure.

    Run the following commands:

    cd /opt
    python3 i2c.py

2.2.2.5 I2C communication using Python programs

  • I2C can be controlled by using the Python smbus library. Run the following command on RUBIK Pi 3 to install the library.

    pip3 install smbus
  • The following code snippet uses the I2C1 bus to communicate with a device whose address is 0x38: write 0xaa to the 0x01 address of the device.

    import smbus

    def main():
    data = [0x01, 0xaa]

    try:
    i2c_bus = smbus.SMBus(1)

    print("i2cdetect addr : ", end="")
    for address in range(0x7F):
    try:
    i2c_bus.write_i2c_block_data(address, 0, data)
    print("0x{:02X},".format(address), end="")
    except OSError:
    pass

    print()

    except Exception as e:
    print(f"An error occurred: {e}")

    finally:
    if i2c_bus:
    i2c_bus.close()

    if __name__ == "__main__":
    main()
  • Transfer i2c.py to RUBUK Pi 3. For example, use the ADB method.

    adb push i2c.py /opt
  • Connect pin 3 and pin 5 to the I2C sensor and test the I2C communication as shown in the following figure.

    Run the following commands:

    cd /opt
    python3 i2c.py

    The execution result is as follows:

2.2.2.6 I2C communication using C programs

  • The following code snippet uses the I2C1 bus to communicate with a device whose address is 0x38: write 0xaa to the 0x01 address of the device.

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <linux/i2c-dev.h>
    #include <sys/ioctl.h>

    #define I2C_DEVICE_PATH "/dev/i2c-1"

    int main() {
    uint8_t data[2] = {0x01,0xaa};

    const char *i2c_device = I2C_DEVICE_PATH;
    int i2c_file;

    if ((i2c_file = open(i2c_device, O_RDWR)) < 0) {
    perror("Failed to open I2C device");
    return -1;
    }

    ioctl(i2c_file, I2C_TENBIT, 0);
    ioctl(i2c_file, I2C_RETRIES, 5);

    printf("i2cdetect addr : ");
    for (int x = 0; x < 0x7f; x++)
    {
    if (ioctl(i2c_file, I2C_SLAVE, x) < 0) {
    perror("Failed to set I2C slave address");
    close(i2c_file);
    return -1;
    }

    if (write(i2c_file, data, 2) == 2)
    {
    printf("0x%x,", x);
    }
    }

    close(i2c_file);
    printf("\r\n");

    return 0;
    }
  • Compile programs:

    • Cross-compile the program. For details, refer to 1.11.3. Use the cross-compilation tools.

      aarch64-qcom-linux-gcc i2c.c -o i2c --sysroot=/home/zhy/qcom_sdk_meta/sysroots/armv8-2a-qcom-linux/
    • Compile on RUBIK Pi 3

      adb push i2c.c /opt
      adb shell
      cd /opt
      gcc i2c.c -o i2c

      If you use cross-compilation, transfer i2c to RUBIK Pi 3. For example, use the ADB method.

      adb push i2c /opt
  • Connect pin 3 and pin 5 to the I2C sensor to test the I2C bus communication, as shown in the following figure.

    Run the following commands:

    cd /opt
    ./i2c

    The program execution result is as follows:

2.2.3 SPI

RUBIK Pi 3 is compatible with WiringRP (based on the high-performance GPIO programming library WiringPi). It is recommended to use WiringRP for controlling and programming SPI. For more details about WiringRP, visit https://github.com/rubikpi-ai/WiringRP.

2.2.3.1 Pinout

The figure below shows the default functions of the RUBIK Pi 3 40-pin LS connector, most of which are compatible with the default functions of the Raspberry Pi 40-pin connector.

note

Pins 19, 21, 23, and 24 are set to SPI by default.

The following table lists all functions of the 40-pin LS connector. Blue bold functions are default functions.

2.2.3.2 SPI communication using WiringRP (C)

The WiringRP library provides a set of API functions that enable control with minimal logic.

  • The following code snippet uses the SPI bus to send and receive data.

    #include <wiringPi.h>
    #include <stdio.h>
    #include <stdlib.h>

    int main(void)
    {
    int fd;
    unsigned char send_data[64] = "hello world!";
    unsigned char read_data[64];

    if(wiringPiSetup() == -1)
    exit(1);

    fd = wiringPiSPISetup(0, 1000000);
    if(fd < 0)
    exit(2);

    printf("\rtx_buffer: \n %s\n ", send_data);
    // Send and receive data
    if(wiringPiSPIDataRW(0, send_data, sizeof(send_data)) < 0)
    exit(3);
    printf("\rtx_buffer: \n %s\n ", send_data);


    return 0;
    }
  • Compile programs

    • Compile on RUBIK Pi 3

      adb push spi.c /opt
      adb shell
      cd /opt
      gcc spi.c -o i2c -lwiringPi
  • Short pin 19 and pin 21 with a Dupont wire to test the SPI bus communication, as shown in the following figure:

    Run the following commands:

    cd /opt
    ./spi

    The execution result is as follows:

2.2.3.3 SPI communication using WiringRP-Python

The WiringRP library provides a set of API functions that enable control with minimal logic.

  • The following code snippet uses the SPI bus to send and receive data:

    import wiringpi as wpi                                                          

    wpi.wiringPiSetup()

    wpi.wiringPiSPISetup(0, 8000000)

    tx_buffer = bytes([72, 101, 108, 108, 111])
    print("tx_buffer:\n\r ", tx_buffer)
    retlen, rx_buffer = wpi.wiringPiSPIDataRW(0, tx_buffer)
    print("rx_buffer:\n\r ", rx_buffer)

  • Transfer spi.py to RUBIK Pi 3. For example, use the ADB method.

    adb push spi.py /opt
  • Short pin 19 and pin 21 with a Dupont wire to test the SPI bus communication, as shown in the following figure:

    Run the following command:

     python3 spi.py 

    The execution result is as follows:

2.2.3.4 SPI communication using Python programs

  • SPI communication can be implemented by using the spidev library for Python. Run the following command to install spidev on RUBIK Pi 3.

    pip3 install spidev
  • The following code snippet uses the SPI bus to send and receive data.

    import spidev

    def main():
    tx_buffer = [ord(char) for char in "hello world!"]
    rx_buffer = [0] * len(tx_buffer)

    try:
    spi = spidev.SpiDev()
    spi.open(12, 0)
    spi.max_speed_hz = 1000000

    rx_buffer = spi.xfer2(tx_buffer[:])
    print("tx_buffer:\n\r", ''.join(map(chr, tx_buffer)))
    print("rx_buffer:\n\r", ''.join(map(chr, rx_buffer)))

    except Exception as e:
    print(f"An error occurred: {e}")

    finally:
    if spi:
    spi.close()

    if __name__ == "__main__":
    main()
  • Transfer spi.py to RUBIK Pi 3. For example, use the ADB method.

    adb push spi.py /opt
  • Short pin 19 and pin 21 with a Dupont wire to test the SPI bus communication, as shown in the following figure.

    Run the following command:

    python3 spi.py

    The program execution result is as follows:

2.2.3.5 SPI communication using C programs

  • The following code snippet uses the SPI bus to send and receive data.

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <linux/spi/spidev.h>
    #include <sys/ioctl.h>

    #define SPI_DEVICE_PATH "/dev/spidev12.0"

    int main() {
    int spi_file;
    uint8_t tx_buffer[50] = "hello world!";
    uint8_t rx_buffer[50];

    // Open the SPI device
    if ((spi_file = open(SPI_DEVICE_PATH, O_RDWR)) < 0) {
    perror("Failed to open SPI device");
    return -1;
    }

    // Configure SPI mode and bits per word
    uint8_t mode = SPI_MODE_0;
    uint8_t bits = 8;
    if (ioctl(spi_file, SPI_IOC_WR_MODE, &mode) < 0) {
    perror("Failed to set SPI mode");
    close(spi_file);
    return -1;
    }
    if (ioctl(spi_file, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0) {
    perror("Failed to set SPI bits per word");
    close(spi_file);
    return -1;
    }

    // Perform SPI transfer
    struct spi_ioc_transfer transfer = {
    .tx_buf = (unsigned long)tx_buffer,
    .rx_buf = (unsigned long)rx_buffer,
    .len = sizeof(tx_buffer),
    .delay_usecs = 0,
    .speed_hz = 1000000, // SPI speed in Hz
    .bits_per_word = 8,
    };

    if (ioctl(spi_file, SPI_IOC_MESSAGE(1), &transfer) < 0) {
    perror("Failed to perform SPI transfer");
    close(spi_file);
    return -1;
    }

    /* Print tx_buffer and rx_buffer*/
    printf("\rtx_buffer: \n %s\n ", tx_buffer);
    printf("\rrx_buffer: \n %s\n ", rx_buffer);

    // Close the SPI device
    close(spi_file);

    return 0;
    }
  • Compile programs:

    • Cross-compile the program. For details, refer to 1.11.3. Use the cross-compilation tools.

      aarch64-qcom-linux-gcc spi.c -o spi --sysroot=/home/zhy/qcom_sdk_meta/sysroots/armv8-2a-qcom-linux/
    • Compile on RUBIK Pi 3

      adb push spi.c /opt
      adb shell
      cd /opt
      gcc spi.c -o spi
    • If you use cross-compilation, transfer spi to RUBIK Pi 3. For example, use the ADB method:

      adb push spi /opt
  • Short pin 19 and pin 21 with a Dupont wire to test the SPI bus communication, as shown in the following figure.

    Run the following commands:

    cd /opt
    ./spi

    The program execution result is as follows:

2.2.4 UART

RUBIK Pi 3 is compatible with WiringRP (based on the high-performance GPIO programming library WiringPi). It is recommended to use WiringRP for controlling and programming UART. For more details about WiringRP, visit https://github.com/rubikpi-ai/WiringRP.

2.2.4.1 Pinout

The figure below shows the default functions of the RUBIK Pi 3 40-pin LS connector, most of which are compatible with the default functions of the Raspberry Pi 40-pin connector.

note

Pins 8 and 10 have been set to UART by default. The device node is /dev/ttyHS3.

The following table lists all functions of the 40-pin LS connector. Blue bold functions are default functions.

2.2.4.2 UART communication using shell commands

Run the following commands on RUBIK Pi 3 to control UART communication.

  • Use the stty tool to configure UART. Run the following commands to set both the input rate and output rate of UART to 115200 and disable the echo.

    stty -F /dev/ttyHS3 ispeed 115200 ospeed 115200  
    stty -F /dev/ttyHS3 -echo
  • Enable the two terminals on RUBIK Pi 3, short pin 8 and pin 10 with a Dupont wire, and run the following commands. The content sent by the transmitter will be displayed on the receiver.

    echo "hello world!" > /dev/ttyHS3 #Transmitter  
    cat /dev/ttyHS3 #Receiver

2.2.4.3 UART communication using WiringRP (C)

The WiringRP library provides a set of API functions that enable control with minimal logic.

  • The following code snippet uses UART to send and receive data:

    #include <stdio.h>
    #include <string.h>
    #include <errno.h>

    #include <wiringPi.h>
    #include <wiringSerial.h>

    int main ()
    {
    int fd ;
    int count ;
    unsigned int nextTime ;

    if ((fd = serialOpen ("/dev/ttyHS3", 115200)) < 0)
    {
    fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
    return 1 ;
    }

    if (wiringPiSetup () == -1)
    {
    fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
    return 1 ;
    }


    char tx_buffer[] = "hello world!\n";
    for (count = 0 ; count < sizeof(tx_buffer) ; count++)
    {
    serialPutchar (fd, tx_buffer[count]) ;
    delay (3) ;
    printf ("%c", serialGetchar (fd)) ;
    }
    printf ("\n") ;

    return 0 ;
    }


  • Compile programs:

    • Compile on RUBIK Pi 3

      adb push uart.c /opt
      adb shell
      cd /opt
      gcc uart.c -o uart
  • Short pin 8 and pin 10 with a Dupont wire and test the communication, as shown in the following figure:

    Run the following commands:

    cd /opt
    ./uart

    The execution result is as follows:

2.2.4.4 UART communication using WiringRP-Python

The WiringRP library provides a set of API functions that enable control with minimal logic.

  • The following code snippet uses UART to send and receive data.

    import wiringpi

    serial = wiringpi.serialOpen('/dev/ttyHS3', 115200)

    wiringpi.serialPuts(serial, "hello world")

    received_data = []
    c = wiringpi.serialGetchar(serial);
    received_data.append(chr(c))

    cnt = wiringpi.serialDataAvail(serial);
    for i in range(cnt):
    c = wiringpi.serialGetchar(serial);
    received_data.append(chr(c))

    print("Received:", received_data)

    wiringpi.serialClose(serial)

  • Transfer uart.py to RUBIK Pi 3. For example, use the ADB method. The command is as follows:

    adb push uart.py /opt
  • Short pin 8 and pin 10 with a Dupont wire to test UART communication, as shown in the following figure:

    Run the following commands:

    cd /opt
    python3 uart.py

    The execution result is as follows:

2.2.4.5 UART communication using Python programs

  • UART communication can be implemented by using the serial library for Python. Run the following command to install the serial library on RUBIK Pi 3.

    pip3 install pyserial
  • Use UART to send and receive data.

    import serial
    import time

    with serial.Serial(
    "/dev/ttyHS3",
    baudrate=115200,
    bytesize=serial.EIGHTBITS,
    stopbits=serial.STOPBITS_ONE,
    parity=serial.PARITY_NONE,
    timeout=1,

    ) as uart3:
    uart3.write(b"Hello World!\n")
    buf = uart3.read(128)
    print("Raw data:\n", buf)
    data_strings = buf.decode("utf-8")
    print("Read {:d} bytes, printed as string:\n {:s}".format(len(buf), data_strings))
  • Transfer uart.py to RUBIK Pi 3. For example, use the ADB method. The command is as follows:

    adb push uart.py /opt
  • Short pin 8 and pin 10 with a Dupont wire to test the UART communication, as shown in the following figure.

    Run the following command:

    python3 uart.py

    The program execution result is as follows:

2.2.4.6 UART communication using C programs

  • Use UART to send and receive data.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <termios.h>
    #include <unistd.h>

    int main() {
    int serial_port_num = 3;
    char serial_port[15];

    sprintf(serial_port,"/dev/ttyHS%d",serial_port_num);
    int serial_fd;

    serial_fd = open(serial_port, O_RDWR | O_NOCTTY);
    if (serial_fd == -1) {
    perror("Failed to open serial port");
    return 1;
    }

    struct termios tty;
    memset(&tty, 0, sizeof(tty));

    if (tcgetattr(serial_fd, &tty) != 0) {
    perror("Error from tcgetattr");
    return 1;
    }

    cfsetospeed(&tty, B9600);
    cfsetispeed(&tty, B9600);

    tty.c_cflag &= ~PARENB;
    tty.c_cflag &= ~CSTOPB;
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;

    if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) {
    perror("Error from tcsetattr");
    return 1;
    }

    char tx_buffer[] = "hello world!\n";
    ssize_t bytes_written = write(serial_fd, tx_buffer, sizeof(tx_buffer));
    if (bytes_written < 0) {
    perror("Error writing to serial port");
    close(serial_fd);
    return 1;
    }
    printf("\rtx_buffer: \n %s ", tx_buffer);

    char rx_buffer[256];
    int bytes_read = read(serial_fd, rx_buffer, sizeof(rx_buffer));
    if (bytes_read > 0) {
    rx_buffer[bytes_read] = '\0';
    printf("\rrx_buffer: \n %s ", rx_buffer);
    } else {
    printf("No data received.\n");
    }

    close(serial_fd);

    return 0;
    }

  • Compile programs:

    • Cross-compile the program. For details, refer to 1.11.3. Use the cross-compilation tools.

      aarch64-qcom-linux-gcc uart.c -o uart --sysroot=/home/zhy/qcom_sdk_meta/sysroots/armv8-2a-qcom-linux/
    • Compile on RUBIK Pi 3

      adb push uart.c /opt
      adb shell
      cd /opt
      gcc uart.c -o uart

      If you use cross-compilation, transfer uart to RUBIK Pi 3. For example, use the ADB method. The command is as follows:

      adb push uart /opt
  • Short pin 8 and pin 10 with a Dupont wire and test the UART communication, as shown in the following figure.

    Run the following commands:

    cd /opt
    ./uart

    The program execution result is as follows:

2.3 USB

RUBIK Pi 3 provides four USB ports:

  • 2 x USB 3.0, host mode only (No.7 in the following figure)

  • 1 x USB 2.0, host or device mode (No. 6 in the following figure)

  • 1 x USB 3.1 Gen 1, host or device mode, Type-C with DisplayPort v1.4 (No. 5 in the following figure)

2.3.1 USB 2.0 Type-A

To switch the USB 2.0 port to device mode, you need to run commands manually. For example, run the following commands on RUBIK Pi 3 to simulate RUBIK Pi 3 as a USB flash drive.

cd /sys/kernel/config/usb_gadget/ #Log in from the serial port and run the following command
mkdir g1
cd g1
mkdir functions/mass_storage.0
dd if=/dev/zero of=/tmp/test.iso bs=1M count=2048 #Create a 2 GB USB drive space
mkfs.ext4 /tmp/test.iso
echo "/tmp/test.iso" > functions/mass_storage.0/lun.0/file
mkdir configs/c.1
ln -s functions/mass_storage.0/ configs/c.1/f3
mount -t debugfs none /sys/kernel/debug/

echo device > /sys/kernel/debug/usb/8c00000.usb/qcom_usb2_0_mode #Switch USB to device mode
echo 8c00000.usb > UDC #Connect the USB cable. The USB drive is identified and can be written to and read from


echo host > /sys/kernel/debug/usb/8c00000.usb/qcom_usb2_0_mode #Remove the USB cable and switch to host mode

2.3.2 USB 3.1 Type-C

The Type-C port can automatically switch between host and device modes.

  • Automatically switches to device mode when connected to PC

  • Automatically switches to host mode when an OTG cable is connected

  • Automatically outputs DP video signals when connected to a DP monitor

2.3.3 USB debugging

This section provides the methods for obtaining debug logs. The debug methods include regdumps, debug ftraces, and configfs nodes. When debugging issues related to entering or exiting low-power modes, system memory management unit (SMMU), and unclocked accesses, you can check the event and controller status details through the logs obtained by using the above methods.

  • USB 2.0 Type-A device path: /sys/devices/platform/soc@0/8c00000.usb/xhci-hcd.0.auto/usb1

  • USB 3.0 Type-A device path:

    • /sys/devices/platform/soc@0/1c00000.pci/pci0000:00/0000:00:00.0/0000:01:00.0/usb2

    • /sys/devices/platform/soc@0/1c00000.pci/pci0000:00/0000:00:00.0/0000:01:00.0/usb3

  • USB 3.1 Type-C device path: /sys/devices/platform/soc@0/a600000.usb

2.3.3.1 USB tracing

Use debugfs to deeply trace each transaction over the USB line. To view the trace list, run the following command.

note

Before running the command, ensure that debugfs has been mounted. If not mounted, run the following command to mount debugfs:

mount -t debugfs none /sys/kernel/debug

ls /sys/kernel/debug/tracing/events/dwc3

The following traces can be used to verify data transmission in the xHCI, gadget stack, or USB Type-C Connector System Software Interface (UCSI).

dwc3_alloc_request  dwc3_event              dwc3_gadget_generic_cmd  enable
dwc3_complete_trb dwc3_free_request dwc3_gadget_giveback filter
dwc3_ctrl_req dwc3_gadget_ep_cmd dwc3_prepare_trb
dwc3_ep_dequeue dwc3_gadget_ep_disable dwc3_readl
dwc3_ep_queue dwc3_gadget_ep_enable dwc3_writel

To list the traces in the xHCI/Host Controller Driver (HCD), run the following command:

ls /sys/kernel/debug/tracing/events/xhci-hcd

The following traces can be used to verify data transmission in the xHCI/HCD.

enable                            xhci_handle_cmd_config_ep
filter xhci_handle_cmd_disable_slot
xhci_add_endpoint xhci_handle_cmd_reset_dev
xhci_address_ctrl_ctx xhci_handle_cmd_reset_ep
xhci_address_ctx xhci_handle_cmd_set_deq
xhci_alloc_dev xhci_handle_cmd_set_deq_ep
xhci_alloc_virt_device xhci_handle_cmd_stop_ep
xhci_configure_endpoint xhci_handle_command
xhci_configure_endpoint_ctrl_ctx xhci_handle_event
xhci_dbc_alloc_request xhci_handle_port_status
xhci_dbc_free_request xhci_handle_transfer
xhci_dbc_gadget_ep_queue xhci_hub_status_data
xhci_dbc_giveback_request xhci_inc_deq
xhci_dbc_handle_event xhci_inc_enq
xhci_dbc_handle_transfer xhci_queue_trb
xhci_dbc_queue_request xhci_ring_alloc
xhci_dbg_address xhci_ring_ep_doorbell
xhci_dbg_cancel_urb xhci_ring_expansion
xhci_dbg_context_change xhci_ring_free
xhci_dbg_init xhci_ring_host_doorbell
xhci_dbg_quirks xhci_setup_addressable_virt_device
xhci_dbg_reset_ep xhci_setup_device
xhci_dbg_ring_expansion xhci_setup_device_slot
xhci_discover_or_reset_device xhci_stop_device
xhci_free_dev xhci_urb_dequeue
xhci_free_virt_device xhci_urb_enqueue
xhci_get_port_status xhci_urb_giveback
xhci_handle_cmd_addr_dev

To list the available events for the USB Video Class (UVC) gadget driver, run the following command:

ls /sys/kernel/debug/tracing/events/gadget

The output is as follows.

enable                      usb_gadget_activate
filter usb_gadget_clear_selfpowered
usb_ep_alloc_request usb_gadget_connect
usb_ep_clear_halt usb_gadget_deactivate
usb_ep_dequeue usb_gadget_disconnect
usb_ep_disable usb_gadget_frame_number
usb_ep_enable usb_gadget_giveback_request
usb_ep_fifo_flush usb_gadget_set_remote_wakeup
usb_ep_fifo_status usb_gadget_set_selfpowered
usb_ep_free_request usb_gadget_vbus_connect
usb_ep_queue usb_gadget_vbus_disconnect
usb_ep_set_halt usb_gadget_vbus_draw
usb_ep_set_maxpacket_limit usb_gadget_wakeup
usb_ep_set_wedge

To list the available events in the UCSI driver, run the following command:

ls /sys/kernel/debug/tracing/events/ucsi

The output is as follows.

enable  ucsi_connector_change  ucsi_register_port  ucsi_run_command
filter ucsi_register_altmode ucsi_reset_ppm

2.3.3.2 USB regdump

The USB debugfs provides the following information (using the Type-C interface as an example)

  • Operating mode

    cat /sys/kernel/debug/usb/a600000.usb/mode # Type-C interface
    note

    Operating mode of USB 2.0 Type-A cat /sys/kernel/debug/usb/8c00000.usb/qcom_usb2_0_mode

    Sample output:

    device
  • State and transfer ring buffer (TRB) queues to all endpoints in device mode.

  • Current link status.

    cat /sys/kernel/debug/usb/a600000.usb/link_state

    Sample output:

    Sleep
  • Display processor (LSP) dump

    cat /sys/kernel/debug/usb/a600000.usb/lsp_dump

    Sample output:

    GDBGLSP[0] = 0x40000000
    GDBGLSP[1] = 0x00003a80
    GDBGLSP[2] = 0x38200000
    GDBGLSP[3] = 0x00802000
    GDBGLSP[4] = 0x126f1000
    GDBGLSP[5] = 0x3a800018
    GDBGLSP[6] = 0x00000a80
    GDBGLSP[7] = 0xfc03f14a
    GDBGLSP[8] = 0x0b803fff
    GDBGLSP[9] = 0x00000000
    GDBGLSP[10] = 0x000000f8
    GDBGLSP[11] = 0x000000f8
    GDBGLSP[12] = 0x000000f8
    GDBGLSP[13] = 0x000000f8
    GDBGLSP[14] = 0x000000f8
    GDBGLSP[15] = 0x000000f8
ls /sys/kernel/debug/usb/a600000.usb

Sample output:

ep0in    ep11out  ep14in   ep1out  ep4in   ep6out  ep9in       regdump
ep0out ep12in ep14out ep2in ep4out ep7in ep9out testmode
ep10in ep12out ep15in ep2out ep5in ep7out link_state
ep10out ep13in ep15out ep3in ep5out ep8in lsp_dump
ep11in ep13out ep1in ep3out ep6in ep8out mode

Run the regdump command to obtain the current status of the register space for the following registers:

  • Device mode registers, such as DCTL, DSTS, and DCFG

  • Global registers, such as GCTL and GSTS

cd /sys/kernel/debug/usb/a600000.usb
cat regdump

Sample output:

GSBUSCFG0 = 0x2222000e
GSBUSCFG1 = 0x00001700
GTXTHRCFG = 0x00000000
GRXTHRCFG = 0x00000000
GCTL = 0x00102000
GEVTEN = 0x00000000
GSTS = 0x7e800000
GUCTL1 = 0x810c1802
GSNPSID = 0x5533330a
GGPIO = 0x00000000
GUID = 0x00060500
GUCTL = 0x0d00c010
GBUSERRADDR0 = 0x00000000
GBUSERRADDR1 = 0x00000000
GPRTBIMAP0 = 0x00000000
GPRTBIMAP1 = 0x00000000
GHWPARAMS0 = 0x4020400a
GDBGFIFOSPACE = 0x00420000
GDBGLTSSM = 0x41090658
GDBGBMU = 0x20300000
GPRTBIMAP_HS0 = 0x00000000
GPRTBIMAP_HS1 = 0x00000000
GPRTBIMAP_FS0 = 0x00000000
GPRTBIMAP_FS1 = 0x00000000
GUCTL2 = 0x0198440d
VER_NUMBER = 0x00000000
VER_TYPE = 0x00000000
GUSB2PHYCFG(0) = 0x00002400
GUSB2I2CCTL(0) = 0x00000000
GUSB2PHYACC(0) = 0x00000000
GUSB3PIPECTL(0) = 0x030e0002
GTXFIFOSIZ(0) = 0x00000042
GRXFIFOSIZ(0) = 0x00000305
GEVNTADRLO(0) = 0xfffff000
GEVNTADRHI(0) = 0x0000000f
GEVNTSIZ(0) = 0x00001000
GEVNTCOUNT(0) = 0x00000000
GHWPARAMS8 = 0x000007ea
GUCTL3 = 0x00010000
GFLADJ = 0x8c80c8a0
DCFG = 0x00cc08b4
DCTL = 0x8cf00a00
DEVTEN = 0x00000257
DSTS = 0x008a5200
DGCMDPAR = 0x00000000
DGCMD = 0x00000000
DALEPENA = 0x0000000f
DEPCMDPAR2(0) = 0x00000000
DEPCMDPAR1(0) = 0xffffe000
DEPCMDPAR0(0) = 0x0000000f
DEPCMD(0) = 0x00000006
OCFG = 0x00000000
OCTL = 0x00000000
OEVT = 0x00000000
OEVTEN = 0x00000000
OSTS = 0x00000000

2.3.3.3 Host mode sysfs lookup

To view the bus detailed information, run the following command:

lsub

Sample output:

Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 03f0:134a HP, Inc Optical Mouse
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

To view the contents of the current directory, run the following commands:

cd /sys/bus/usb/devices/
ls

Sample output:

1-0:1.0  1-1  1-1:1.0  2-0:1.0  usb1  usb2

To view detailed information about USB devices, run the following command:

cat /sys/kernel/debug/usb/devices

Sample output:

T:  Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#=  1 Spd=480  MxCh= 1
B: Alloc= 0/800 us ( 0%), #Int= 0, #Iso= 0
D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=1d6b ProdID=0002 Rev= 6.05
S: Manufacturer=Linux 6.5.0-rc4 xhci-hcd
S: Product=xHCI Host Controller
S: SerialNumber=xhci-hcd.0.auto
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 4 Ivl=256ms

T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=1.5 MxCh= 0
D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=03f0 ProdID=134a Rev= 1.00
S: Manufacturer=PixArt
S: Product=HP USB Optical Mouse
C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=100mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=usbhid
E: Ad=81(I) Atr=03(Int.) MxPS= 4 Ivl=10ms

T: Bus=02 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=5000 MxCh= 1
B: Alloc= 0/800 us ( 0%), #Int= 0, #Iso= 0
D: Ver= 3.00 Cls=09(hub ) Sub=00 Prot=03 MxPS= 9 #Cfgs= 1
P: Vendor=1d6b ProdID=0003 Rev= 6.05
S: Manufacturer=Linux 6.5.0-rc4 xhci-hcd
S: Product=xHCI Host Controller
S: SerialNumber=xhci-hcd.0.auto
C:* #Ifs= 1 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub
E: Ad=81(I) Atr=03(Int.) MxPS= 4 Ivl=256ms

2.4 CSI

Currently, RUBIK Pi 3 is compatible with three Raspberry Pi cameras. The following table lists the supported resolutions for each camera module.

ResolutionAspect RatioIMX477IMX708IMX219
4056 x 30404:3YesNoNo
4608 x 259216:9NoYesNo
3280 x 24644:3NoNoYes
1920 x 108016:9YesNoNo
1632 x 12244:3NoNoYes
  • Raspberry Pi High Quality Camera (IMX477/M12 Mount) Purchase link

    In the demonstration in Chapter 4. Qualcomm IM SDK, the IMX477 camera uses the WS1053516 lens.

  • Raspberry Pi Camera Module 2 (IMX219) Purchase link

    note

    Currently, RUBIK Pi 3 only supports the standard Camera Module 2 and does not support the wide-angle or NoIR versions.

  • Raspberry Pi Camera Module 3 (IMX708) Purchase link

    note

    Currently, RUBIK Pi 3 only supports the standard Camera Module 3 and does not support the wide-angle or NoIR versions. The current software version does not support the autofocus (AF) function of the Module 3 camera.

2.4.1 Connect the camera cable

RUBIK Pi 3 supports the 22-pin FPC with a 0.5mm pitch and a 0.3±0.05mm thickness. It is compatible with the Raspberry Pi 5 FPC of the same specification.

  1. Pull up the lock of the connector.

  2. Insert the FPC. Ensure that the contacts are toward the center of RUBIK Pi 3.

  1. Press the lock down to ensure that the FPC is properly connected.

2.4.2 Use cameras

The camera can be operated by using the GStreamer command on RUBIK Pi 3. Before an operation, run the following commands to set the camera.

echo multiCameraLogicalXMLFile=kodiak_dc.xml > /var/cache/camera/camxoverridesettings.txt
echo enableNCSService=FALSE >> /var/cache/camera/camxoverridesettings.txt

Run the following commands to enable or disable the camera-related logging. After running the commands, restart your RUBIK Pi 3 for the setting to take effect.

Default values:

  • logWarningMask:0xFFFFFFFFFFFFFFFF

  • logCoreCfgMask:0xFFFFFFFFFFFFFFFF

echo logWarningMask=0x00 >> /var/cache/camera/camxoverridesettings.txt
echo logCoreCfgMask=0x00 >> /var/cache/camera/camxoverridesettings.txt

Connect cameras to connectors 13 and 14 in the following figure.

The following picture shows the physical connection:

note

Currently, running two IMX708 at 4608 x 2592 simultaneously is not supported.

  • Run the following commands on RUBIK Pi 3 for the full-screen preview of a single camera:

    export XDG_RUNTIME_DIR=/dev/socket/weston  
    export WAYLAND_DISPLAY=wayland-1
    setprop persist.overlay.use_c2d_blit 2
    gst-launch-1.0 -e qtiqmmfsrc camera=0 name=camsrc ! video/x-raw\(memory:GBM\),format=NV12,width=1920,height=1080,framerate=30/1,compression=ubwc ! queue ! waylandsink fullscreen=true async=true

The following figure shows the preview result:

  • Run the following commands on RUBIK Pi 3 for the concurrent preview of two cameras:

    # Terminal 1  
    export XDG_RUNTIME_DIR=/dev/socket/weston
    export WAYLAND_DISPLAY=wayland-1
    setprop persist.overlay.use_c2d_blit 2
    gst-launch-1.0 -e qtiqmmfsrc camera=0 name=camsrc ! video/x-raw\(memory:GBM\),format=NV12,width=1920,height=1080,framerate=30/1,compression=ubwc ! queue ! waylandsink sync=false x=0 y=0 width=960 height=540 enable-last-sample=false

    # Terminal 2
    export XDG_RUNTIME_DIR=/dev/socket/weston
    export WAYLAND_DISPLAY=wayland-1
    setprop persist.overlay.use_c2d_blit 2
    gst-launch-1.0 -e qtiqmmfsrc camera=1 name=camsrc ! video/x-raw\(memory:GBM\),format=NV12,width=1920,height=1080,framerate=30/1,compression=ubwc ! queue ! waylandsink sync=false x=960 y=540 width=960 height=540 enable-last-sample=false

    The following figure shows the preview result:

  • Run the following commands on RUBIK Pi 3 for concurrent video recording from both cameras.

    # Terminal 1:   
    echo multiCameraLogicalXMLFile=kodiak_dc.xml > /var/cache/camera/camxoverridesettings.txt
    export XDG_RUNTIME_DIR=/dev/socket/weston
    export WAYLAND_DISPLAY=wayland-1
    setprop persist.overlay.use_c2d_blit 2
    gst-launch-1.0 -e qtiqmmfsrc camera=0 name=camsrc video_0::type=preview ! video/x-raw\(memory:GBM\),format=NV12,width=1920,height=1080,framerate=30/1,compression=ubwc,interlace-mode=progressive,colorimetry=bt601 ! queue ! v4l2h264enc capture-io-mode=5 output-io-mode=5 ! queue ! h264parse ! mp4mux ! queue ! filesink location="/opt/mux0.mp4"
    # Terminal 2:
    export XDG_RUNTIME_DIR=/dev/socket/weston
    export WAYLAND_DISPLAY=wayland-1
    setprop persist.overlay.use_c2d_blit 2
    gst-launch-1.0 -e qtiqmmfsrc camera=1 name=camsrc video_0::type=preview ! video/x-raw\(memory:GBM\),format=NV12,width=1920,height=1080,framerate=30/1,compression=ubwc,interlace-mode=progressive,colorimetry=bt601 ! queue ! v4l2h264enc capture-io-mode=5 output-io-mode=5 ! queue ! h264parse ! mp4mux ! queue ! filesink location="/opt/mux1.mp4"

    The recorded video files are saved in the /opt directory.

  • Run the following commands on RUBIK Pi 3 for concurrent preview and video recording from two cameras.

    # Terminal 1  
    export XDG_RUNTIME_DIR=/dev/socket/weston
    export WAYLAND_DISPLAY=wayland-1
    setprop persist.overlay.use_c2d_blit 2
    gst-launch-1.0 -e qtiqmmfsrc camera=0 name=camsrc video_0::type=preview ! video/x-raw\(memory:GBM\),format=NV12,width=1920,height=1080,framerate=30/1,compression=ubwc,interlace-mode=progressive,colorimetry=bt601 ! queue ! v4l2h264enc capture-io-mode=5 output-io-mode=5 ! queue ! h264parse ! mp4mux ! queue ! filesink location="/opt/mux0.mp4" camsrc. ! video/x-raw\(memory:GBM\),format=NV12,width=1920,height=1080,framerate=30/1,compression=ubwc ! waylandsink sync=false x=0 y=0 width=960 height=540 enable-last-sample=false

    # Terminal 2
    export XDG_RUNTIME_DIR=/dev/socket/weston
    export WAYLAND_DISPLAY=wayland-1
    setprop persist.overlay.use_c2d_blit 2
    gst-launch-1.0 -e qtiqmmfsrc camera=1 name=camsrc video_0::type=preview ! video/x-raw\(memory:GBM\),format=NV12,width=1920,height=1080,framerate=30/1,compression=ubwc,interlace-mode=progressive,colorimetry=bt601 ! queue ! v4l2h264enc capture-io-mode=5 output-io-mode=5 ! queue ! h264parse ! mp4mux ! queue ! filesink location="/opt/mux1.mp4" camsrc. ! video/x-raw\(memory:GBM\),format=NV12,width=1920,height=1080,framerate=30/1,compression=ubwc ! waylandsink sync=false x=960 y=540 width=960 height=540 enable-last-sample=false

    The recorded video files are saved in the /opt directory.

    The following figure shows the preview result:

  • Run the following commands on RUBIK Pi 3 to test the camera photo function:

    export XDG_RUNTIME_DIR=/dev/socket/weston
    export WAYLAND_DISPLAY=wayland-1
    setprop persist.overlay.use_c2d_blit 2
    gst-pipeline-app -e qtiqmmfsrc name=camsrc camera=0 ! "image/jpeg,width=1920,height=1080,framerate=30/1" ! multifilesink location=/opt/0_frame%d.jpg max-files=1

    After executing the above commands, the following MENU is displayed in the terminal. Type "3" in the MENU and press Enter to take photos.


    ##################################### MENU #####################################

    ============================== Pipeline Controls ==============================
    (0) NULL : Set the pipeline into NULL state
    (1) READY : Set the pipeline into READY state
    (2) PAUSED : Set the pipeline into PAUSED state
    (3) PLAYING : Set the pipeline into PLAYING state
    ==================================== Other ====================================
    (p) Plugin Mode : Choose a plugin which to control
    (q) Quit : Exit the application


    Choose an option:

    # Press CTRL+C to stop taking photos

    The captured photos are saved in the /opt directory.

2.4.3 Troubleshoot camera issues

If the camera fails to display or capture images, check the following contents:

  1. Check the camera module connection.

    For details, refer to 2.4.1 Connect the camera cable.

  2. Run the single-stream preview test case.

    export XDG_RUNTIME_DIR=/dev/socket/weston
    export WAYLAND_DISPLAY=wayland-1
    setprop persist.overlay.use_c2d_blit 2
    gst-launch-1.0 -e qtiqmmfsrc camera=0 name=camsrc ! video/x-raw\(memory:GBM\),format=NV12,width=1920,height=1080,framerate=30/1,compression=ubwc ! queue ! waylandsink sync=false x=1000 y=1000 width=960 height=540 enable-last-sample=false
  3. Run the following command to collect logs.

    journalctl -f > /opt/log.txt

    Search for "probe success" in the logs. "probe success" indicates that the camera module is powered on and responding to I2C control. If the sensor does not have the "probe success" log, the possible cause is the flex cable connection or camera module issue.

    The following log indicates that an IMX477 is detected:

    [   80.645992] CAM_INFO: CAM-SENSOR: cam_sensor_driver_cmd: 939: Probe success,slot:7,slave_addr:0x34,sensor_id:0x477, is always on: 0
  4. Check the camera sensor driver command.

    Collect logs using the journalctl -f > /opt/log.txt command and search for "cam_sensor_driver_cmd" in the logs. "CAM_START_DEV Success" indicates that the camera sensor streaming started. "CAM_STOP_DEV Success" indicates that the camera sensor streaming has stopped. For example:

    start:
    [ 81.172814] CAM_INFO: CAM-SENSOR: cam_sensor_driver_cmd: 1129: CAM_START_DEV Success, sensor_id:0x477,sensor_slave_addr:0x34
    stop:
    [ 88.905241] CAM_INFO: CAM-SENSOR: cam_sensor_driver_cmd: 1157: CAM_STOP_DEV Success, sensor_id:0x477,sensor_slave_addr:0x34
  5. Check the sensor streaming.

    Enable the CSID SOF/EOF IRQ logs, then execute the camera streaming command.

    mount -o rw,remount /usr
    mount -t debugfs none /sys/kernel/debug/
    echo 0x8 > /sys/module/camera/parameters/debug_mdl
    echo 3 >/sys/kernel/debug/camera_ife/ife_csid_debug
    echo 1 > /sys/kernel/tracing/tracing_on
    echo 1 > /sys/kernel/tracing/events/camera/cam_log_debug/enable
    echo 2 > /sys/module/camera/parameters/debug_type
    cat /sys/kernel/tracing/trace_pipe > trace.txt

    The captured logs provide detailed information about the Start of Frame (SOF) and End of Frame (EOF). In the trace.txt log, search for "irq_status_ipp".

    • BIT12 (0x1000) represents the SOF packet.

    • BIT9 (0x200) represents the EOF packet.

    The log will appear as follows:

    <idle>-0       [000] d.h1. 19287.546764: cam_log_debug:
    CAM_DBG: CAM-ISP: cam_ife_csid_irq: 4996: irq_status_ipp = 0x1110 cam-server-25604 [000] dNH.. 19287.561705: cam_log_debug:
    CAM_DBG: CAM-ISP: cam_ife_csid_irq: 4996: irq_status_ipp = 0xee8

2.5 HDMI OUT

The HDMI connector is component No.9 in the following figure.

RUBIK Pi 3 HDMI specifications are as follows:

  • HDMI 1.4

  • 3840 x 2160@30 fps

  • DSI 0 to HDMI (lt9611)

  • Supports CEC

  • Supports resolution auto-adjustment

  • Supports hot swapping

note

DP and HDMI can be connected to a monitor simultaneously for concurrent display.

2.5.1 CEC

HDMI Consumer Electronics Control (CEC) is a feature of HDMI designed to interconnect and control multiple connected devices via a single HDMI cable. CEC facilitates communication between connected devices through a dedicated CEC pin. For example, multiple devices can be controlled with a single remote control.

RUBIK Pi 3 integrates the cec-client tool. After connecting the HDMI cable to a TV, run the following command to check whether the TV supports CEC.

echo 'scan' | cec-client -s -d 1

If the TV supports CEC, you will see the following output:

opening a connection to the CEC adapter...
requesting CEC bus information ...
CEC bus information
===================
device #0: TV
address: 0.0.0.0
active source: no
vendor: Sony
osd string: TV
CEC version: 1.4
power status: standby
language: eng


device #1: Recorder 1
address: 1.0.0.0
active source: no
vendor: Pulse Eight
osd string: CECTester
CEC version: 1.4
power status: on
language: eng


device #4: Playback 1
address: 3.0.0.0
active source: no
vendor: Sony
osd string: PlayStation 4
CEC version: 1.3a
power status: standby
language: ???

If the TV supports the CEC function, run the following commands on RUBIK Pi 3 to increase or decrease the TV volume.

echo 'volup' | cec-client -t p -s  
echo 'voldown' | cec-client -t p -s

For more information about how to use cec-client, use the -h parameter.

2.5.2 HDMI OUT touchscreen

RUBIK Pi 3 supports HDMI OUT touchscreen with 1024 x 600P resolution by default:

info

The screen used in the picture above is a 7" IPS HD touch screen.

2.5.3 HDMI OUT debugging

RUBIK Pi 3 uses the LT9611 DSI-to-HDMI bridge chip.

The following table lists the configurations required for integrating the bridge.

2.5.3.1 Obtain lt9611 logs

Run the following command to obtain lt9611 logs:

dmesg | grep lt9611

Check the logs. The following message indicates that HDMI OUT is functioning properly.

This log records the initialization of the LT9611 chip and the HDMI connection process, from firmware version detection to CEC initialization, indicating that the chip has started normally.

  1. The firmware version of the chip is 0xe2.17.02. This indicates that during initialization, the driver successfully reads the version information.

  2. The Consumer Electronics Control (CEC) function adapter of the LT9611 has been successfully registered.

  3. CEC initialization is complete, which means that the CEC module of LT9611 is functioning properly.

  4. The chip successfully reads the Hot Plug Detection (HPD) status, and a value is returned, confirming the connection of the HDMI device.

  5. The chip detects the video signal parameters: horizontal resolution 1920 pixels, vertical resolution 1080 pixels, and pixel clock frequency 148500 kHz (148.5 MHz). This is a typical 1080p resolution (Full HD) with a 60 Hz refresh rate configuration.

[    5.492765] lt9611 9-0039: LT9611 revision: 0xe2.17.02
[ 5.570258] lt9611 9-0039: CEC adapter registered
[ 5.582944] lt9611 9-0039: CEC init success

[ 8.233028] lt9611 9-0039: success to read hpd status: 13
[ 8.233044] lt9611_device_connect_status_notify: send msg[Hdmi Connection] ret[32]
[ 8.345015] lt9611 9-0039: hdisplay=1920, vdisplay=1080, clock=148500
[ 8.836662] lt9611 9-0039: video check: hactive_a=1920, hactive_b=1920, vactive=1080, v_total=1125, h_total_sysclk=401, mipi_video_format=170

2.5.3.2 Obtain DSI logs

The output DSI information can also be used for debugging. DSI stands for Display Serial Interface, which is typically related to display drivers for mobile devices or embedded systems (such as MIPI DSI).

The following command is used to view kernel logs related to DSI for debugging display drivers or hardware issues.

dmesg | grep dsi

Sample output:


[ 4.811430] i2c 9-0039: Fixed dependency cycle(s) with /soc@0/qcom,dsi-display-primary
[ 4.941131] dsi_phy ae94400.qcom,mdss_dsi_phy0: supply gdsc not found, using dummy regulator
[ 4.941385] [drm:dsi_pll_init [msm_drm]] [msm-dsi-info]: DSI_PLL_0: DSI pll label = dsi_pll_5nm
[ 4.941466] [drm:dsi_pll_init [msm_drm]] [msm-dsi-info]: DSI_PLL_0: PLL SSC enabled
[ 4.941513] dsi_pll_init: PLL base=00000000625eaee4
[ 4.941658] [drm:dsi_pll_clock_register_5nm [msm_drm]] [msm-dsi-info]: DSI_PLL_0: Registered clocks successfully
[ 4.941700] [drm:dsi_phy_driver_probe [msm_drm]] [msm-dsi-info]: DSI_0: Probe successful
[ 4.973185] [drm:dsi_ctrl_dev_probe [msm_drm]] [msm-dsi-info]: dsi-ctrl-0: Probe successful

[ 5.585113] [drm:dsi_display_bind [msm_drm]] [msm-dsi-info]: Successfully bind display panel 'qcom,mdss_dsi_ext_bridge_1080p '
[ 5.585154] msm_drm ae00000.qcom,mdss_mdp0: bound soc@0:qcom,dsi-display-primary (ops dsi_display_comp_ops [msm_drm])
[ 8.345467] [drm:dsi_display_set_mode [msm_drm]] [msm-dsi-info]: mdp_transfer_time=0, hactive=1920, vactive=1080, fps=60, clk_rate=0
[ 8.345740] [drm:dsi_ctrl_isr_configure [msm_drm]] [msm-dsi-info]: dsi-ctrl-0: IRQ 249 registered

2.5.3.3 View display panel information

Run the following command to view the information of the specified display panel.

cat /sys/kernel/debug/qcom,mdss_dsi_ext_bridge_2k60/dump_info

Sample output:

name = qcom,mdss_dsi_ext_bridge_2k60
Resolution = 2560(80|48|32|1)x1440(33|3|5|1)@60fps 0 Hz
CTRL_0:
ctrl = dsi-ctrl-0
phy = dsi-phy-0
Panel = ext video mode dsi bridge
Clock master = dsi-ctrl-0

2.5.3.4 View DSI clock information

Run the following command to view DSI clock information.

cat /sys/kernel/debug/qcom,mdss_dsi_ext_bridge_2k60/dsi-ctrl-0/state_info

Sample output:

Current State:
CTRL_ENGINE = ON
VIDEO_ENGINE = ON
COMMAND_ENGINE = OFF

Clock Info:
BYTE_CLK = 181274400, PIXEL_CLK = 241699200, ESC_CLK = 19200000

2.5.3.5 View regulator information

Run the following command to view the regulator status and voltage.

cat /sys/kernel/debug/regulator/regulator_summary

2.5.3.6 View interface information

To retrieve the debug dump output (display interface number, VSync count, underload count, and interface mode), run the following command:

cat /sys/kernel/debug/dri/0/encoder*/status

Sample output:

intf:1    vsync:  359036     underrun:       0    mode: video
intf:0 vsync: 0 underrun: 0 mode: video

2.5.3.7 Common DPU debug information

The common Display Processing Unit (DPU) debug information is explained as follows:

Run the following command to check the DPU clock rate:

cat /sys/kernel/debug/clk/clk_summary | grep disp_cc

Set the DPU to performance mode.

cd /sys/kernel/debug/dri/0/debug/core_perf/
echo 1 > perf_mode

2.6 DP

RUBIK Pi 3 provides a USB Type-C that supports DisplayPort (DP) over Single-Stream Transport (SST), labeled as No. 5 in the following figure.

The DP specifications are as follows:

  • 3840 × 2160@60 fps
  • Single stream transport
  • Simultaneous operation of DP and USB 3.0

note

DP and HDMI can be connected to a monitor simultaneously for concurrent display.

2.6.1 DP debugging

2.6.1.1 Obtain DP logs

Run the following command to enable log printing.

echo 8 > /proc/sys/kernel/printk 
echo ‘file dsi* +p’ > /sys/kernel/debug/dynamic_debug/control
note

8 in the first command is the log level. In the Linux kernel, log levels are represented by numbers from 0 to 8. The smaller the number, the higher the priority. The levels are described as follows:

  • 0 (KERN_EMERG): System emergency (e.g., crash).
  • 1 (KERN_ALERT): Issues that require immediate attention.
  • 2 (KERN_CRIT): Critical errors.
  • 3 (KERN_ERR): General errors.
  • 4 (KERN_WARNING): Warnings.
  • 5 (KERN_NOTICE): Normal events that are noteworthy.
  • 6 (KERN_INFO): Informational messages.
  • 7 (KERN_DEBUG): Debugging information.
  • 8: A level lower than debugging, displaying all levels of logs.

Running the second command echo ‘file dsi* +p’ > /sys/kernel/debug/dynamic_debug/control will display the debug information from all kernel source files whose filenames start with dsi* (usually related to DSI display driver code). This debug information will be output to the kernel log, which can be viewed by running dmesg. The following command output can be used for DP debugging:

mount -t debugfs none /sys/kernel/debug
echo 'file dp_display.c +p' > /sys/kernel/debug/dynamic_debug/control
echo 'file dp_aux.c +p' > /sys/kernel/debug/dynamic_debug/control
echo 'file dp_link.c +p' > /sys/kernel/debug/dynamic_debug/control
echo 'file dp_power.c +p' > /sys/kernel/debug/dynamic_debug/control
echo 'file dp_ctrl.c +p' > /sys/kernel/debug/dynamic_debug/control
echo 'file dp_parser.c +p' > /sys/kernel/debug/dynamic_debug/control

After printing all levels of logs, filter DP logs for further validation. The following output shows the logs for a successful DP startup.

hub 4-0:1.0: USB hub found
hub 4-0:1.0: 1 port detected
usb usb5: We don't know the algorithms for LPM for this host, disabling LPM.
hub 5-0:1.0: USB hub found
hub 5-0:1.0: 1 port detected
[drm:dp_power_clk_enable][msm-dp-info][3216]core:on link:off strm0:off strm1:off
[drm:dp_display_host_init][msm-dp-info][3216][OK]
[drm:dp_display_host_ready][msm-dp-info][2912][OK]
[drm:dp_panel_read_sink_caps][msm-dp-info][2912]fec_en=0, dsc_en=0, widebus_en=0
[drm:dp_link_process_request][msm-dp-info][2912]event: DP_LINK_STATUS_UPDATED
[drm:dp_power_clk_enable][msm-dp-info][2912]core:on link:on strm0:off strm1:off
[drm:dp_catalog_ctrl_fec_config][msm-dp-err][2912]no link
[drm:dp_ctrl_link_train][msm-dp-info][2912]link training #1 successful
[drm:dp_ctrl_link_train][msm-dp-info][2912]link training #2 successful
[drm:dp_link_process_request][msm-dp-info][2912]event: DP_LINK_STATUS_UPDATED
[drm:dp_catalog_ctrl_fec_config][msm-dp-err][2912]no link
[drm:dp_ctrl_link_train][msm-dp-info][2912]link training #1 successful
[drm:dp_ctrl_link_train][msm-dp-info][2912]link training #2 successful
[drm:dp_display_send_hpd_event][msm-dp-info][2912][name=DP-1]:[status=connected] [bpp=0] [pattern=0]
[drm:dp_display_send_hpd_event][msm-dp-info][2912]uevent success: 0
lt9611 9-0039: success to read hpd status: 8
lt9611_device_connect_status_notify: send msg[Hdmi Disconnect] ret[32]
lt9611 9-0039: success to read hpd status: 8
lt9611_device_connect_status_notify: send msg[Hdmi Disconnect] ret[32]
[drm:dp_power_clk_enable][msm-dp-info][577 ]core:on link:on strm0:on strm1:off
[drm:dp_catalog_ctrl_fec_config][msm-dp-err][577 ]no link
[drm:dp_ctrl_link_train][msm-dp-info][577 ]link training #1 successful
[drm:dp_ctrl_link_train][msm-dp-info][577 ]link training #2 successful
[drm:dp_panel_resolution_info][msm-dp-info][577 ]DP RESOLUTION: active(back|front|width|low)
[drm:dp_panel_resolution_info][msm-dp-info][577 ]1920(148|88|44|0)x1080(36|4|5|0)@60fps 24bpp 148500Khz 10LR 2Ln

The above logs for a successful DP startup are summarized as follows:

  1. USB initialization: The system detects two single-port USB hubs during startup and disables the LPM of USB 5.
  2. DP preparation: The DP controller is initialized, the display capabilities are read, and preparations are made to establish a connection.
  3. DP link training: Multiple link training attempts are made to establish a stable connection between the DP and the display.
  4. DP connection confirmation: The system confirms that DP-1 is connected and notifies the user space.
  5. HDMI disconnection: LT9611 detects HDMI disconnection, which may be due to user action or interface switching.
  6. DP output: After HDMI disconnection, DP enables video streaming and outputs 1080p@60 Hz video.

2.7 Wi-Fi and Bluetooth

RUBIK Pi 3 is equipped with the AP6256 Wi-Fi module and supports Wi-Fi 5 and Bluetooth 5.2.

2.7.1 Wi-Fi

2.7.1.1 Operating bands

The AP6256 Wi-Fi chipset supports 2.4 GHz and 5 GHz operating bands.

2.7.1.2 Operating modes

The Wi-Fi software operates in the following modes.

2.7.1.2.1 STA mode

In Station (STA) mode, the device can be connected to an existing Wi-Fi network to access network resources or the Internet. Run the following commands on RUBIK Pi 3:

  1. Scan for nearby Wi-Fi.

    iw wlan0 scan | grep SSID
  2. Connect to Wi-Fi.

    wpa_passphrase <ssid> <passphrase> > /etc/wpa_supplicant.conf #Enter the Wi-Fi account and password
    systemctl restart wifi #Connect to Wi-Fi

    The device will automatically connect to the Wi-Fi network the next time it is started.

  3. If you want to switch to another Wi-Fi network, modify the /etc/wpa_supplicant.conf file. The following example shows a modification method:

    ctrl_interface=/var/run/wpa_supplicant
    update_config=1
    pmf=1
    network={
    ssid="RUBIKPi"
    psk="123456789"
    }
    • ssid is the Wi-Fi network name.

    • psk is the Wi-Fi network password.

    Modify the .conf file based on your actual situation.

  1. After modifying the configuration, run the following commands to connect to the Wi-Fi network.

    killall -9 wpa_supplicant  
    wpa_supplicant -Dnl80211 -iwlan0 -c/etc/wpa_supplicant.conf -B
2.7.1.2.2 Wireless mode

In Access Point (AP) mode, namely, the wireless hotspot mode, the device becomes a gateway for other devices to connect to a network. The steps to create an AP are as follows:

  • Enable the AP.

    1. Create or modify hostapd.conf.

      ctrl_interface=/var/run/hostapd
      driver=nl80211
      ieee80211n=1
      interface=wlan1
      hw_mode=a
      channel=36
      beacon_int=100
      dtim_period=1
      ssid=RUBIKPi
      auth_algs=1
      ap_isolate=0
      ignore_broadcast_ssid=0
      wpa=2
      wpa_key_mgmt=WPA-PSK
      rsn_pairwise=CCMP
      wpa_passphrase=123456789
    2. Run the following commands to enable the AP:

      hostapd -B /opt/hostapd.conf # Set the software AP
      # Enable the DHCP server
      brctl addbr br0
      brctl addif br0 wlan1
      ifconfig br0 192.168.225.1 netmask 255.255.255.0 up
      killall dnsmasq
      dnsmasq --conf-file=/etc/dnsmasq.conf --dhcp-leasefile=/var/run/dnsmasq.leases --addn-hosts=/data/hosts --pid-file=/var/run/dnsmasq.pid -i br0 -I lo -z --dhcp-range=br0,192.168.225.20,192.168.225.60,255.255.255.0,43200 --dhcp-hostsfile=/data/dhcp_hosts --dhcp-option-force=6,192.168.225.1 --dhcp-script=/bin/dnsmasq_script.sh
    3. Run the following command to establish a connection with hostapd_cli.

      hostapd_cli -i wlan1 -p /var/run/hostapd

      Monitor Wi-Fi STA connection notifications in the hostapd_cli console, such as AP-STA-CONNECTED and EAPOL-4WAY-HS-COMPLETED.

      Sample output:

      root@rubikpi:~# hostapd_cli -i wlanl -p /var/run/hostapd
      hostapd_cli v2.11-devel
      Copyright (c) 2004-2022, Jouni Malinen <j@wl.fi> and contributors
      This software may be distributed under the terms of the BSD License.
      See README for more details.

      Interactive mode
      > <3>AP-STA-CONNECTED aa: a4: fd: 8b: ec: 90
      <3>EAPOL-4WAY-HS-COMPLETED aa: a4: fd: 8b:ec:90

      > list_sta
      aa: a4: fd: 8b:ec:90

    Before the AP 5G mode is enabled, if there has never been a connection to a 5G Wi-Fi network using STA, use the following command to check the 5G channel configuration in the environment:

    iw dev wlan0 scan

    In the command output, identify the currently active channel through the primary channel field. In the following example, the value of primary channel is 36. Write 36 into the channel field in the /opt/hostapd.conf file.

    HT operation:
    * primary channel: 36
    * secondary channel offset: above
    * STA channel width: any
    * RIFS: 0
    * HT protection: nonmember
    * non-GF present: 0
    * OBSS non-GF present: 0
    * dual beacon: 0
    * dual CTS protection: 0
    * STBC beacon: 0
    * L-SIG TXOP Prot: 0
    * PCO active: 0
    * PCO phase: 0
  • Verify AP

    To test the connection, connect to AP from other devices.

    For example, perform the following steps to connect to AP from a mobile device:

    1. On the mobile device, go to Wi-Fi settings.

    2. Wait for the Wi-Fi STA to detect AP.

    3. Select AP and type the corresponding wpa_passphrase configured for AP on your RUBIK Pi 3 device for connection.

    > status
    state=ENABLED
    phy=phyR freq=2412
    num_sta_non_erp=0
    num_sta_no_short_slot_time=0
    num_sta_no_short_preamble=0
    olbc=0
    num_sta_ht_no_gf=0 num_sta_no_ht=0
    num_sta_ht_20_mhz=0
    num_sta_ht40_intolerant=0
    olbc_ht=0
    ht_op_mode=0x0
    hw_mode=g
    country_code=US
    country3=0x20
    cac_time_seconds=0
    cac_time_left_seconds=N/A
    channel=1
    edmg_enable=0 edmg_channel=0
    secondary_channel=0
    ieee80211n=1
    ieee80211ac=0
    ieee80211ax=0
    ieee80211be=0
    beacon_int=100
    dtim_period=2
    ht_caps_info=000c
    ht_mcs_bitmask=ffff0000000000000000
    supported_rates-02 04 0b 16 Oc 12 18 24 30 48 60 6c
    max_txpower=30
    bss[0]=wlan1
    bssid[0]=00:03:7f:95:8e:8e
    ssid [0]=QSoftAP
    num_sta[0]=1
    > |

    To verify the connection, ping the IP address of the mobile device from the RUBIK Pi 3 device in the ssh shell.

    The following output indicates that the Wi-Fi connection has been established successfully and the data transfer has begun:

    sh-5.1# ping 192.168.1.42
    PING 192.168.1.42 (192.168.1.42): 56 data bytes
    64 bytes from 192.168.1.42: seq=0 ttl=64 time-11.175 ms
    64 bytes from 192.168.1.42: seq=1 ttl=64 time=14.528 ms
    64 bytes from 192.168.1.42: seq=2 ttl=64 time=29.735 ms
    64 bytes from 192.168.1.42: seq=3 ttl=64 time=223.822 ms
    64 bytes from 192.168.1.42: seq-4 ttl=64 time-23.675 ms
    ^C
    192.168.1.42 ping statistics ---
    7 packets transmitted, 5 packets received, 28% packet loss
    round-trip min/avg/max = 11.175/60.587/223.822 ms
    sh-5.1#

    Alternatively, you can verify the Wi-Fi connection status in Settings of the connected device. For example, to get the IP address of a mobile device connected to RUBIK Pi 3 AP, perform the following steps:

    1. Go to Settings > Wi-Fi.

    2. Verify the SSID of the AP.

  • Stop AP:

    Perform the following steps in SSH to disable AP:

    1. Stop the hostapd by performing the following steps:

      1. Run the following command to stop the hostapd process:

        killall hostapd
      2. Run the following command to disable the interface:

        ifconfig wlan1 down
    2. Run the following command to delete ctrl_interface:

      rm -rf /var/run/hostapd/wlan1

      The Wi-Fi hotspot has stopped successfully.

2.7.2 BT

Run the following commands on RUBIK Pi 3 to test the Bluetooth function.

  • Run the app_manager program to pair devices:

    cd /usr/src/rubikpi-btapp/  
    ./app_manager

    1. In the terminal, type "2", press Enter, and wait for the Bluetooth scan result.

    2. In the terminal, type "4", press Enter, type the dev number of the Bluetooth device to be paired, and press Enter again.

    3. In the terminal, type "13" to accept the pairing. The Bluetooth device to be paired also needs to accept the pairing request.

    app_manager must be running at all times. Run the adb shell command to create a terminal and perform the following steps.

  • Transmission via Bluetooth.

    Take sending a file as an example:

    cd /usr/src/rubikpi-btapp/  
    touch ./test_file.txt
    echo RUBIKPi > test_file.txt
    ./app_opc
    #Type 4 and press Enter
    #Type 0 and press Enter
    #Type the dev number and press Enter
    #Phone receives file
    #Type 9 and press Enter to quit

  • Reception via Bluetooth

    cd /usr/src/rubikpi-btapp/  
    mkdir push
    ./app_ops
    #Type 1 and press Enter
    #Phone sends file via Bluetooth
    #After transmission, type 9 and press Enter to quit. The transmitted file is located in the ./push folder

  • Other demos

    All the BT-related source code is stored in the following directory of RUBIK Pi 3: /usr/src/rubikpi-bt-demo/3rdparty/3rdparty/embedded/bsa_examples/linux. Compile and view the code as needed. The following example shows the compilation method:

    cd /usr/src/rubikpi-bt-demo/3rdparty/3rdparty/embedded/bsa_examples/linux/<test demo>/build/  
    export ARMGCC=gcc
    make CPU=arm64
    cp arm64/<demo executable file> /usr/src/rubikpi-btapp/
    cd /usr/src/rubikpi-btapp/
    #Run the demo

2.8 Audio

RUBIK Pi 3 currently supports the following audio interfaces:

  • 3.5mm headphone (No. 4 in the following figure)
  • HDMI OUT (No. 9 in the following figure)
  • Bluetooth

2.8.1 View the sound card information

  • Run the following command on RUBIK Pi 3 to view the mounted sound cards:

    cat /proc/asound/cards

  • Run the following command on RUBIK Pi 3 to view the list of allocated Pulse-Code Modulation (PCM) streams:

    cat /proc/asound/pcm

2.8.2 Set the audio output device

Run the following commands on RUBIK Pi 3 to change the audio output source for commands such as gstreamer and paplay:

  • Set the 3.5mm headset as the output interface:

    pactl set-sink-port low-latency0 headset
  • Set the HDMI OUT as the output interface:

    pactl set-sink-port low-latency0 hdmi

2.8.3 Playback

  • Run the following command on RUBIK Pi 3 to test headset playback.

    note

    Before running the following command, put the MP3 test file (<FileName>.mp3) in the /opt directory.

    gst-launch-1.0 filesrc location=/opt/<FileName>.mp3 ! mpegaudioparse ! mpg123audiodec ! pulsesink
  • Run the following command on RUBIK Pi 3 to test HDMI OUT playback.

    note

    Before running the following command, put the PCM test file (<FileName>.wav) in the /opt directory.

    systemctl stop pulseaudio  
    agmplay /opt/<FileName>.wav -D 100 -d 100 -r 48000 -b 16 -c 2 -i MI2S-LPAIF_RXTX-RX-PRIMARY
    systemctl start pulseaudio
  • Run the following commands on RUBIK Pi 3 to test Bluetooth playback. You need to open multiple terminals.

    1. Terminal 1:

      cd /usr/src/rubikpi-btapp/  
      ./app_manager

    2. Terminal 2:

      cd /usr/src/rubikpi-btapp/  
      ./app_av

      1. Type "2" and press Enter. Wait for the Bluetooth device to be found.
      2. Type "6" and press Enter to start establishing a connection.
      3. Type "1" and press Enter to connect to a recently scanned device.
      4. Type the dev number of the Bluetooth device you want to connect.
    3. Go to Terminal 1 and type "13" to accept the pairing.

    4. Go to Terminal 2, type "11", and press Enter. Select the number of the piece of music you want to play and press Enter.

2.8.4 Recording

Run the following commands on RUBIK Pi 3 to test the recording function.

  • Headset recording

    gst-launch-1.0 -v pulsesrc volume=10 ! audioconvert ! wavenc ! filesink location=/opt/test.wav
  • Test the Bluetooth headset recording. You need to open multiple terminals.

    1. Terminal 1:

       cd /usr/src/rubikpi-btapp/  
      ./app_manager

    2. Terminal 2:

      cd /usr/src/rubikpi-btapp/  
      ./app_ag

      1. Type "1" and press Enter. Wait for the Bluetooth device to be found.

      2. Type "6" and press Enter to connect the Bluetooth headset.

      3. Type "1" and press Enter to connect to a recently scanned device.

      4. Type the dev number of the Bluetooth device you want to connect.

    3. Go to Terminal 1 and type "13" to accept the pairing.

    4. Go to Terminal 2 and type "8" to open the SCO link.

    5. Go to terminal 3 and run the following commands to start recording:

    systemctl stop pulseaudio

    #Start recording audio from the Bluetooth headset microphone.
    agmcap /home/root/my.wav -D 100 -d 101 -r 16000 -b 16 -c 1 -i MI2S-LPAIF_VA-TX-PRIMARY -dkv 0xA3000003 -p 120 -n 2

    #Press CTRL+C to stop recording.

    systemctl start pulseaudio

    The recorded audio is located at /home/root/my.wav.

2.8.5 Volume up/down

  • Adjust the headphone volume

    Run the following commands to obtain and set the volume:

        tinymix get "DAC Playback Volume"  

    tinymix set "DAC Playback Volume" 192 192

  • Adjust the Bluetooth volume

    While playing Bluetooth audio, you can control the volume in terminal 2.

    1. Type 20

    2. Type 0

    3. Type the volume (from 0 to 100).

2.8.6 Capture logs

  • User space logs

    Perform the following operations to capture user space logs:

    ssh root@ip-addr
    mount -o remount,rw /
    cat /var/log/user.log
  • Kernel audio driver logs

    • Kernel logs

      dmesg
    • Disable kernel logs in a specific file:

      echo –n “file <filename> -p” > /sys/kernel/debug/dynamic_debug/control
    • Dynamic kernel logs

      By default, dynamic logging is disabled. To enable it, add the CONFIG_DYNAMIC_DEBUG kernel configuration, then recompile and reflash the device.

      To enable audio dynamic kernel logs, perform the following steps:

      ssh root@ip-addr
      mount -o rw,remount /
      mount -t debugfs none /sys/kernel/debug
      echo –n “file <filename> +p” > /sys/kernel/debug/dynamic_debug/control

2.8.7 Analyze the captured logs

View user space and kernel audio driver logs to learn about playback and recording use cases.

  • Playback

    The following log snippet describes the information collected for the playback use case.

    //Open Low latency Playback stream. Details of each stream type can be found at sources/audio/opensource/arpal-lx/inc/PalDefs.h
    2022-04-28T18:02:08.748280+00:00 pulseaudio: pal_stream_open: 224: Enter, stream type:1

    //Verify the backend device, sample rate, bitwidth, channels etc
    2022-04-28T18:02:08.748627+00:00 pulseaudio: setDeviceMediaConfig: 1056: CODEC_DMA-LPAIF_WSA-RX-0 rate ch fmt data_fmt 48000 2 2 1

    //Start playback stream
    2022-04-28T18:02:08.751947+00:00 pulseaudio: pal_stream_start: 338: Enter. Stream handle 0xffff94001040K

    //Map the metadata with kvh2xml.h file for playback usecase details.
    2022-04-28T18:02:08.853157+00:00 pulseaudio: metadata_print: 82 key:0xa1000000, value:0xa100000e//PCM_LL_PLAYBACK
    2022-04-28T18:02:08.853395+00:00 pulseaudio: metadata_print: 82 key:0xab000000, value:0x1
    2022-04-28T18:02:08.853660+00:00 pulseaudio: metadata_print: 82 key:0xa2000000, value:0xa2000001//Speaker
    2022-04-28T18:02:08.853881+00:00 pulseaudio: metadata_print: 82 key:0xac000000, value:0xac000002//DEVICEPP_RX_AUDIO_MBDRC

    //Verify the graph opened for playback usecase
    2022-04-28T18:02:08.856934+00:00 pulseaudio: print_graph_alias: 2334 GKV Alias 142 | StreamRX_PCM_LL_Playback_DeviceRX_Speaker_Instance_Instance_1_DevicePP_Rx_Audio_MBDRC
    //graph_open called
    2022-04-28T18:02:08.859509+00:00 pulseaudio: graph_open: 709 graph_handle 0x47534c

    //Configure hardware endpoint module
    2022-04-28T18:02:08.864386+00:00 pulseaudio: configure_hw_ep_media_config: 636 entry mod tag c0000004 miid 43b1 mid 7001023
    2022-04-28T18:02:08.864495+00:00 pulseaudio: configure_hw_ep_media_config: 664 rate 48000 bw 16 ch 2, data_fmt 1
    2022-04-28T18:02:08.864603+00:00 pulseaudio: configure_hw_ep_media_config: 676 exit, ret 0

    //graph_start entry
    2022-04-28T18:02:08.867234+00:00 pulseaudio: graph_start: 899 entry graph_handle 0x47534c
    //Stream started
    2022-04-28T18:02:08.867864+00:00 pulseaudio: pal_stream_start: 387: Exit. status 0

    //graph_stop entry
    2022-04-28T18:02:25.037338+00:00 pulseaudio: graph_stop: 928 entry graph_handle 0x47534c
    //Stop the PAL stream once playback completes
    2022-04-28T18:02:25.039923+00:00 pulseaudio: pal_stream_stop: 441: Exit. status 0

    //graph_close entry
    2022-04-28T18:02:25.050944+00:00 pulseaudio: graph_close: 762 entry handle 0x47534c
    //Close the PAL stream
    2022-04-28T18:02:25.054510+00:00 pulseaudio: pal_stream_close: 322: Exit. status 0

  • Recording

    The following log snippet describes the information collected for the recording use case.

    //Open Recording stream for PAL_STREAM_RAW. Details of stream type can be found at sources/audio/opensource/arpal-lx/inc/PalDefs.h
    Apr 29 09:23:11 pulseaudio[862]: pal_stream_open: 224: Enter, stream type:9

    //Verify the backend device, sample rate, bitwidth, channels etc
    Apr 29 09:23:11 pulseaudio[862]: setDeviceMediaConfig: 1056: CODEC_DMA-LPAIF_VA-TX-0 rate ch fmt data_fmt 48000 1 2 1

    //Start recording stream
    Apr 29 09:23:11 pulseaudio[862]: pal_stream_start: 338: Enter. Stream handle 0xffff6c001040K

    //graph_open entry
    Apr 29 09:23:11 pulseaudio[862]: graph_open: 709 graph_handle 0x47534c

    //Metadata details to identify the usecase
    Apr 29 09:23:11 pulseaudio[862]: metadata_print: 82 key:0xb1000000, value:0xb1000009//RAW_RECORD
    Apr 29 09:23:11 pulseaudio[862]: metadata_print: 82 key:0xa3000000, value:0xa3000004//HANDSETMIC

    //Verify the graph opened for recording usecase
    Apr 29 09:23:11 pulseaudio[862]: print_graph_alias: 2334 GKV Alias 29 | DeviceTX_Handset_Mic_StreamTX_RAW_Record

    //Configure hardware endpoint module
    Apr 29 09:23:11 pulseaudio[862]: configure_hw_ep_media_config: 636 entry mod tag c0000005 miid 43af mid 7001024
    Apr 29 09:23:11 pulseaudio[862]: configure_hw_ep_media_config: 664 rate 48000 bw 16 ch 1, data_fmt 1
    Apr 29 09:23:11 pulseaudio[862]: configure_hw_ep_media_config: 676 exit, ret 0

    //graph_start entry
    Apr 29 09:23:11 pulseaudio[862]: graph_start: 899 entry graph_handle 0x47534c
    //Stream recording started
    Apr 29 09:23:11 pulseaudio[862]: pal_stream_start: 387: Exit. status 0


    //graph_stop entry
    Apr 29 09:23:26 pulseaudio[862]: graph_stop: 928 entry graph_handle 0x47534c
    //Stop the PAL stream once user stops recording
    Apr 29 09:23:26 pulseaudio[862]: D: [regular2] pal-source.c: pal_stream_stop returned 0

    //Close the PAL stream
    Apr 29 09:23:26 pulseaudio[862]: pal_stream_close: 284: Enter. Stream handle :0xffff6c001040K
    //graph_close entry
    Apr 29 09:23:26 pulseaudio[862]: graph_close: 762 entry handle 0x47534c
    //Close the PAL stream
    Apr 29 09:23:26 pulseaudio[862]: pal_stream_close: 322: Exit. status 0

2.9 Fan

RUBIK Pi 3 is compatible with the Raspberry Pi Active Cooler.

warning

When using RUBIK Pi 3 in high-load or high-performance scenarios, use cooling measures to ensure that the performance of the device is stable. Otherwise, performance may fluctuate due to high CPU temperatures.

2.9.1 Install the fan

  1. Remove all the thermal pads on the back of the cooler and cut the following two pads in the shape of SoC and uMCP of RUBIK Pi 3.

The dimensions of the two pieces are about 14 x 12mm and 13 x 11.5mm.

  1. Paste the two thermal pads to the corresponding positions on RUBIK Pi 3.

  1. Install the cooler and connect the fan cable.

warning

We recommend that you do not remove the fan after installing it on your RUBIK Pi 3. Removal will cause the fan's push pins and thermal pads to degrade and may result in product damage. If the push pins are damaged or deformed or if they do not clip securely, stop using the fan.

2.9.2 Control the fan

The fan of RUBIK Pi 3 controls the speed according to the CPU temperature. You can also run the following commands on RUBIK Pi 3 to control the fan speed. 0 and 255 indicate the maximum and minimum speed of the fan.

echo 100 > /sys/class/hwmon/hwmon29/pwm1
echo 255 > /sys/class/hwmon/hwmon29/pwm1
echo 0 > /sys/class/hwmon/hwmon29/pwm1

2.10 LED

RUBIK Pi 3 features an RGB tri-color LED driven by the PMIC. By default, the green LED is set as a heartbeat indicator to reflect the system's operation status and CPU load. When the CPU load is high, the heartbeat indicator blinks frequently.

  • Turn off the heartbeat LED

    echo none > /sys/class/leds/green/trigger 
  • Turn on the heartbeat LED

    echo heartbeat > /sys/class/leds/green/trigger
  • Set the brightness of the green LED (from 0 to 511. The following example sets it to 100)

    echo 100 >  /sys/class/leds/green/brightness
  • Set the brightness of the red LED (from 0 to 511. The following example sets it to 100)

    echo 100 >  /sys/class/leds/red/brightness
  • Set the brightness of the blue LED (from 0 to 511. The following example sets it to 100)

    echo 100 >  /sys/class/leds/blue/brightness

2.11 Ethernet

The Ethernet interface is port 8 in the following figure. RUBIK Pi 3 supports Gigabit Ethernet.

Connect the network cable, as shown in the following figure:

Run the following command on RUBIK Pi 3 to check the network connection. As shown in the following figure, the IP address has been successfully assigned, indicating that the network connection is successful:

2.11.1 Ethernet debugging

Use the following types of logs to record and debug Ethernet-related issues.

  • dmesg: Debug issues related to kernel drivers.

  • tcpdump: Verify packet transmission.

To debug potential issues that may occur during Ethernet setup, perform the following steps:

  1. To collect dmesg logs and debug issues related to the kernel driver, run the following command:

    dmesg > /var/log/dmesg_logs.txt
  2. To collect tcpdump logs and verify packet transmission, run the following command:

    tcpdump -i any -s 0 -w /var/log/tcpdump.pcap
  3. Collect the output from the ethtool, ifconfig, netstat, and IP routing table for debugging.

2.12 RTC battery connector

The real-time clock (RTC) battery connector is port 1 in the following figure.

Connect the RTC battery as shown in the following figure and write the time into the system hardware clock of RUBIK Pi 3. This way, the system time of RUBIK Pi 3 can be saved even if it is completely powered off.

Write the system time to the system hardware clock on RUBIK Pi 3 as follows:

date -s "08:00:00 20241201" # Set system time to 08:00, December 1, 2024
hwclock -w # Write system time to system hardware clock

2.13 M.2 Key M connector

RUBIK Pi 3 provides an M.2 slot for NVMe storage, which can be used to install a 2280 (22 x 80mm) SSD hard drive. The M.2 Key M slot supports PCIe Gen3 x 2 and can deliver an output of up to 3.3V 2A. The switch of the M.2 connector can be individually controlled.

The M.2 Key M connector uses the PCIe1 bus of the QCS6490. The device path is: /sys/bus/pci/devices/0001:00:00.0.

The M.2 Key M connector is connector 18 in the following figure:

The M.2 Key M connector is compatible with the 2280 SSD, as shown in the following figures:

At present, RUBIK Pi 3 does not support the automatic mounting of SSDs. Run the following commands on RUBIK Pi 3 to mount SSDs manually.

mkdir /opt/ssd
mount /dev/nvme0n1 /opt/ssd

2.13.1 PCIe power management

PCIe defines two types of power management methods:

  • Software power management, which determines the power management features for each device and manages them individually.

  • Systems that do not require software intervention, such as Active State Power Management (ASPM).

When no data packets are being transmitted on the PCIe link, the device puts the PCIe link into a low-power state.

PCIe power management defines the following L0 link states:

  • L0: working state

  • L0s: ASPM state with low-resume latency (energy saving standby state)

2.13.1.2 PCIe device states

PCIe power management defines the following device states:

  • D0 (mandatory): The device is fully ON. There are two sub-states.

    • D0(uninitialized): The function is in D0 (uninitialized) state when waiting for enumeration and configuration after exiting the reset state.

    • D0(active)

      • The function enters the D0(active) state once the enumeration and configuration process is completed.

      • The function enters the D0(active) state when the system software enables one or more (in any combination) function parameters, such as memory space enable, I/O space enable, or BME bits.

  • D1 (optional): light sleep state

    • The function can only initiate the PME message and cannot initiate other TLPs.

    • The function can only serve as the target for configuration transactions, not for other transactions.

    • The function enters the D1 state via a software command that sets the PM control and status registers.

  • D2 (optional): deep sleep state

    • The function can only issue PME messages and cannot issue other TLPs.

    • The function can only serve as the target for configuration transactions, not for other transactions.

    • The function enters the D2 state via software commands that set the PM control and status registers.

  • D3 (mandatory): The device is in the lowest power state, and this function must support two types of D3 states:

  • D3(hot)

    • The function can only issue PME messages and cannot issue other TLPs.

    • The function can only serve as the target for configuration transactions, not for other transactions.

    • The function enters D3(hot) state by issuing a software command that sets the power state field.

  • D3(cold): The device enters the D3(cold) state and is powered off. When power is restored, the device enters the D0(uninitialized) state.

2.13.2 PCIe debugging

The M.2 Key M connector uses the PCIe1 bus of the QCS6490. The device path is: /sys/bus/pci/devices/0001:00:00.0.

The lspci and setpci commands are native to Linux distributions. These two commands provide multiple levels of output and can also be used to view the capabilities and states of different components trained on the PCI bus at a given time. Most of these capabilities reflect the configuration space registers required by the PCIe basic specification. For more detailed information, visit https://pcisig.com/specifications. To view the usage instructions, run the following command:

lspci --help

The following features help in debugging PCIe issues:

  • Display device information.

    lspci

    Sample output:

    0000:00:00.0 PCI bridge: Qualcomm Device 010b
    0000:01:00.0 USB controller: Renesas Technology Corp. uPD720201 USB 3.0 Host Controller (rev 03)
    0001:00:00.0 PCI bridge: Qualcomm Device 010b
  • Show PCIe device and vendor IDs in the device control registers.

    lspci -nvmm

    Sample output

    Slot:        00:00.0
    Class: 0604
    Vendor: 17cb
    Device: 010b
    IOMMUGroup: 6

    Slot: 01:00.0
    Class: 0c03
    Vendor: 1912
    Device: 0014
    Rev: 03
    ProgIf: 30
    IOMMUGroup: 6

    Slot: 0001:00:00.0
    Class: 0604
    Vendor: 17cb
    Device: 010b
    DTNode: /sys/firmware/devicetree/base/soc@0/pci@1c08000/pcie@1
    IOMMUGroup: 7