Monthly Archives: July 2022

Screen: Special Command

The screen has some special commands which can be used to control its brightness and flip the screen, but because the command is not compatible for all type of screen, so test it before use it. Here is a reference for use such command.

For fbusb driver, we have a file named command in /sys folder, we can use it to send the command.

# turn off backlight
echo -e '\x00\x51\x02\x00\x00\x00\x00\x00' > `find /sys/devices/platform/ -name command`
# set backlight brightness to max
echo -e '\x00\x51\x02\x00\x00\x00\xff\x00' > `find /sys/devices/platform/ -name command`
# set backlight brightness to 128(half)
echo -e '\x00\x51\x02\x00\x00\x00\x80\x00' > `find /sys/devices/platform/ -name command`

Here is an example of libusb.

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

#include <libusb-1.0/libusb.h>

static libusb_context *context = NULL;
static libusb_device_handle *handle = NULL;

unsigned char cmd_rotate[] = {0x00, 0x36, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char cmd_backlight[] = {0x00, 0x51, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};

int main(int argc, char *argv[])
{   
    if (argc != 3) {
        printf("usage: send_cmd [cmd: m|b] [param]\n");
        printf("example: mirror by axis x,y [0,1,2,3]\n\tsend_cmd m 1\n");
        printf("example: set backlight [0~255]\n\tsend_cmd b 120\n");
        return 0;
    }
    
    libusb_init(&context);
    handle = libusb_open_device_with_vid_pid(context, 0xc872, 0x1004);
    if (handle == NULL) {
        printf("no device.\n");
        return -1;
    }

    libusb_claim_interface(handle, 0);
    libusb_set_interface_alt_setting(handle, 0, 0);
    
    switch (argv[1][0]) {
    case 'm':
        cmd_rotate[6] = atoi(argv[2]);
        libusb_control_transfer(handle, 0x40, 0xb0, 0, 0, cmd_rotate, 8, 100);
        break;
        
    case 'b':
        cmd_backlight[6] = atoi(argv[2]);
        libusb_control_transfer(handle, 0x40, 0xb0, 0, 0, cmd_backlight, 8, 100);
        break;
        
    default:
        printf("command is not supported.");
        break;
    }
        
    libusb_release_interface(handle, 0);
    libusb_close(handle);
    libusb_exit(context);
    return 0;
}

Also please check https://vocore.io/screen.html, the v2scrctl source code for libusb.

Screen: I2C to Drive RGB LEDs

Currently our V7B board has I2C interface exported, and actually we can control it through USB port.

Note: This I2C mainly is used for upgrade firmware on the usb bus, so it might be risk to use, if you send wrong data to it, it might broken firmware.

Here is the I2C API, only three commands:

#define CMD_SCREEN_I2C          0xb5
#define CMD_SCREEN_I2C_WR 0xb6
#define CMD_SCREEN_I2C_RD 0xb7

0xb5 [i2c address 1byte] [write size 1byte] [read size 1byte] [write data …] this is used to tell i2c bus how many data we will write and how many data we will read then follows the data we will write to i2c, that data will save to a buffer.

0xb6 [i2c address 1byte] this is used to trigger write, send address to it then I2C will write data from its buffer to external device.

0xb7 this is used to read the data from device i2c, it will return the required data bytes(0xb5 read size) max one time can send/receive 58 – 5 = 53bytes, so for data better not to exceed 53 bytes.

Here is the example of writing data to I2C EEPROM, BLOCK_SIZE = 16.

        if (load_from_file(argv[2], buf, 0x2000) < 0) {
            printf("no firmware file.\n");
            return -1;
        }
        
        for (pos = 0; pos < 0x2000; pos += BLOCK_SIZE) {
            cmd[0] = EEPROM_ADDR;    // I2C address
            cmd[1] = BLOCK_SIZE + 2; // write 18 bytes for register address 2byte and data 16byte.
            cmd[2] = 0;              // read zero byte, no read for i2c write.
            cmd[3] = pos >> 8;       // write first byte, register address 
            cmd[4] = pos;            // write second byte, register address
            // put rest data to the buffer.
            memcpy(cmd + 5, buf + pos, BLOCK_SIZE);
            // send i2c command head to screen, require control the i2c bus.
            ret = libusb_control_transfer(handle, 0x40, CMD_SCREEN_I2C, 0, 0, cmd, BLOCK_SIZE + 5, 200);
            // write register address and data to i2c bus.
            ret = libusb_control_transfer(handle, 0xc0, CMD_SCREEN_I2C_WR, 0, 0, cmd, 1, 200);
            
            if (pos % 0x100 == 0) {
                printf(".");
                fflush(stdout);
            }
        }

Here is the example of reading data from I2C EEPROM

        for (pos = 0; pos < 0x2000; pos += BLOCK_SIZE) {
            cmd[0] = EEPROM_ADDR; // I2C address
            cmd[1] = 2;           // write two bytes for register address.
            cmd[2] = BLOCK_SIZE;  // read 16 bytes
            cmd[3] = pos >> 8;    // write data first byte
            cmd[4] = pos;         // write data second byte
            
            ret = libusb_control_transfer(handle, 0x40, CMD_SCREEN_I2C, 0, 0, cmd, 5, 200);
            // write register address to i2c bus.
            ret = libusb_control_transfer(handle, 0xc0, CMD_SCREEN_I2C_WR, 0, 0, cmd, 1, 200);
            // read data from i2c bus.
            ret = libusb_control_transfer(handle, 0xc0, CMD_SCREEN_I2C_RD, 0, 0, cmd, BLOCK_SIZE + 1, 200);
            
            memcpy(buf + pos, cmd + 1, BLOCK_SIZE);
            if (pos % 0x100 == 0) {
                printf(".");
                fflush(stdout);
            }
        }

With this I2C interface, we can easy control RGB LED driver chip like AW9523 and other chips. Then it will save a lot of cost make customized board, do not need arduino and USBhub chip anymore.

To be continue…

Screen: 7inch ready

After months hard work, the 7inch(6.8in exactly) screen is ready in time. 🙂

This screen is pretty special, because the screen main design target is for real car but not like our current 4inch/5inch screen for consumer usage. So it can stand even worse environment like hot area over 65C.

Here is its shape: