Daily Archives: 2022-07-21

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…