全志平台Tina系统led控制芯片is31fl3236调试(以R18 linux4.4内核为例)

2024-02-02 14:58:02 浏览数 (2)

is31fl3236是一款很牛逼的led控制芯片,最多可以控制36通路的led灯,配合智能音箱的麦克风阵列使用,效果非常酷炫,目前市面上很多主流的智能音箱都有用它,比如:天猫精灵、腾讯听听等。

is31fl3236是通过i2c控制的,R18上的i2c驱动是调好的。

github上可以找到is31fl3236这一类led控制芯片的通用驱动,但是这里我们可以用内核提供的i2c-dev.c来构建,用系统给我们提供的i2c-dev.c来实现一个i2c适配器的设备文件,然后通过在应用层操作i2c适配器来控制i2c设备。

(https://www.cnblogs.com/liugf05/archive/2012/12/04/2801951.html)

i2c-dev.c并没有针对特定的设备而设计,只是提供了通用的read()、write()和ioctl()等接口,应用层可以借用这些接口访问挂接在适配器上的i2c设备的存储空间或寄存器,并控制I2C设备的工作方式。但是read和write方法适用性有限。

所以用ioctl方法来操作:

一般都不会使用i2c-dev.c的read()、write()方法。最常用的是ioctl()方法。ioctl()方法可以实现上面所有的情况(两种数据格式、以及I2C算法和smbus算法)。

 针对i2c的算法,需要熟悉struct i2c_rdwr_ioctl_data 、struct i2c_msg。使用的命令是I2C_RDWR。     

代码语言:javascript复制
   struct i2c_rdwr_ioctl_data 

    {

             struct i2c_msg __user *msgs; /* pointers to i2c_msgs */

              __u32 nmsgs; /* number of i2c_msgs */
          };
        struct i2c_msg {
            _ _u16 addr; /* slave address */
            _ _u16 flags; /* 标志(读、写) */ 
            _ _u16 len; /* msg length */
            _ _u8 *buf; /* pointer to msg data */
        };

针对smbus算法,需要熟悉struct i2c_smbus_ioctl_data。使用的命令是I2C_SMBUS。对于smbus算法,不需要考虑“多开始信号时序”问题。

代码语言:javascript复制
       struct i2c_smbus_ioctl_data {
            __u8 read_write; //读、写
            __u8 command; //命令
            __u32 size; //数据长度标识
            union i2c_smbus_data __user *data; //数据
        }

        首先在内核中已经包含了对s3c2410 中的i2c控制器(总线驱动)驱动的支持。提供了i2c算法(非smbus类型的,所以后面的ioctl的命令是I2C_RDWR)

代码语言:javascript复制
        static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
            .master_xfer = s3c24xx_i2c_xfer,
            .functionality = s3c24xx_i2c_func,
        };

另外一方面需要确定为了实现对AT24C02 e2prom的操作,需要确定从机芯片的地址及读写访问时序。

调试时可以选择make menuconfig下的i2c调试工具,如i2cget, i2cset, i2cdetect等,在

Base system ->  busybox -> Miscellaneous -> ...下

led demo源码:

代码语言:javascript复制
// #include <stdarg.h>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
// #include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <sys/ioctl.h>
#include <endian.h>
#include <iostream>

#include <unistd.h>
#include <sys/syscall.h>   /* For SYS_xxx definitions */


#define SLAVE_ADDRESS       0x3F
#define ADDRESS_LENGTH  2
#define DATA_LENGTH         2

#define I2C_DUMP

static int led_hI2cDevice;
static char led_devname[20]="/dev/i2c-1";

static unsigned char  led_bChipAddress;                   /*Specify the i2c chip address*/
static unsigned char  led_bAddressOffset;


#ifdef I2C_DUMP
static int debugflag = 1;
#else
static int debugflag = 0;
#endif


void sys_mdelay(unsigned int ms_delay)
{
    usleep(ms_delay*1000);
}

int i2c_write(unsigned char reg_address, unsigned char val)
{
    struct i2c_rdwr_ioctl_data packets;
    struct i2c_msg msg[1];
    unsigned char led_i2c_buf[2];
    unsigned int write_len = 2; //Addr   Data 2 bytes
    int fd = led_hI2cDevice;
    int ret = 0;
    int i;

    // led_i2c_buf[0] = SLAVE_ADDRESS;
    led_i2c_buf[0] = reg_address;
    led_i2c_buf[1] = val;

    msg[0].addr = led_bChipAddress;
    msg[0].flags = 0; //7 bits
    msg[0].len = write_len;
    msg[0].buf = led_i2c_buf;

    packets.msgs = msg;
    packets.nmsgs = 1;

    if (debugflag)
    {
        printf("I2C: <START> X", led_bChipAddress<<1);
        for(i=0;i<msg[0].len ;i  )
        {
            printf(" X",(0xff& led_i2c_buf[i]) );
        }
        printf(" <STOP>n");
    }

    ret = ioctl(fd,I2C_RDWR, (unsigned long)&packets);



    if (ret < 0) {
        printf(" Failed: i2c_write error = %d (%s)n", ret, strerror(errno));
        return -1;
    }
    return 0;
}


int i2c_init (unsigned char slave_address, int address_offset)
{
    int i2cdev  =  0;
    char *devname = NULL;

    led_bChipAddress = slave_address;
    led_bAddressOffset = address_offset;
/*    g_cbMaxI2cWrite = DEF_MAX_I2C_WRITE_LEN;
    g_cbMaxI2cRead = DEF_MAX_I2C_READ_LEN;*/

    devname = led_devname;

    i2cdev = open(devname, O_RDWR);

    printf("DEV I2C: open i2c device from %sn",devname);

    if( i2cdev < 0 )
    {
        fprintf(stderr, "I2c device [%s] is not present.n",devname);
        return -ENODEV;
    }

    led_hI2cDevice = i2cdev;
    return i2cdev;
}

int  i2c_close (void)
{
    close(led_hI2cDevice);

    return 0;
}
    unsigned char pwm_value = 0xFF;
    unsigned char pwm_half_value = 0x66;
    unsigned char config_value = 0x01;
    unsigned char reset_value = 0x00;

int global_en() {
    i2c_write(0x4A, 0);
}
int global_disable() {
    i2c_write(0x4A, 1);
}

int boot_stage_one() {
    int i = 0;
    int blue_start = 0x24;
    while(1) {
        i2c_write(blue_start, pwm_half_value);
        i2c_write(blue_start - 3, pwm_half_value);
        i2c_write(0x25, reset_value);
        i2c_write(blue_start - 1, pwm_half_value);
        i2c_write(blue_start - 4, pwm_half_value);
        i2c_write(0x25, reset_value);
        sys_mdelay(100);
        i2c_write(blue_start - 1, reset_value);
        if (blue_start - 4 <= 0) {
            blue_start = 0x24;
        } else {
            blue_start -= 3;
        }
    }
}

int boot_stage_two() {

    int i = 0;
    int blue_start = 0x24;
    while(1) {

        i2c_write(blue_start, pwm_half_value);
        i2c_write(0x25, reset_value);
        i2c_write(blue_start - 1, pwm_half_value);
        i2c_write(blue_start - 4, pwm_half_value);
        i2c_write(0x25, reset_value);
        sys_mdelay(100);
        i2c_write(blue_start - 1, reset_value);
        if (blue_start - 3 <= 0) {
            blue_start = 0x24;
        } else {
            blue_start -= 3;
        }
    }
}


int blue_single_loop(unsigned int msec) {

    int i = 0;
    for (i = 0x24; i > 0; i -= 3) {
        i2c_write(i, pwm_half_value);
        i2c_write(0x25, reset_value);
        sys_mdelay(msec); /*change this value to set different patterns*/
        i2c_write(i, reset_value);
    }  //blue
}

int blue_backgroud(unsigned int msec) {

    int i = 0;
    for (i = 0x24; i > 0; i -= 3) {
        i2c_write(i, 96);
        i2c_write(0x25, reset_value);
        sys_mdelay(msec); /*change this value to set different patterns*/
    }  //blue
}

int dirction_arrival(unsigned int sector) {
    // sector has 10 available values , to simplify, just set 1 to 10
    if (sector < 0 || sector > 11) {
        printf("sector is only valid from 0 to 11");
        return -1;
    }
    blue_backgroud(0); //blue_backgroud

    unsigned int sector_start = (sector   6) % 12;
    /* it can be reuse*/
    printf("sector_start = %dn", (int)sector_start);
    int left_start, right_start;

    if (0 == sector_start) {
        left_start = 0x23;
        right_start = 0x02;
    } else if(11 == sector_start) {
        left_start = 0x02;
        right_start = 0x05;
    } else {
        left_start = (12 - sector_start) * 3 - 1;
        right_start = (12 - sector_start   1) * 3 - 1;
    }
    printf("left_start = %d, right_start = %dn", left_start, right_start);
    /*fix me*/
    for (int i = 0; i < 5;   i) {


        i2c_write(left_start, pwm_half_value);
        i2c_write(right_start, pwm_half_value);
        i2c_write(0x25, reset_value);
        sys_mdelay(100);
        i2c_write(left_start, reset_value);
        i2c_write(right_start, reset_value);
        if (left_start - 3 <= 0) {
            left_start = 35;
        } else
            left_start = left_start - 3;
        if (right_start   3 >= 36) {
            right_start = 2;
        } else
            right_start = right_start   3;
    }
    i2c_write(left_start, pwm_half_value);
    i2c_write(right_start, pwm_half_value);
    i2c_write(0x25, reset_value);
    return 0;
}

int dynamic_doa(unsigned int updated_sector) {
    blue_backgroud(0);
    int left_start, right_start;

    if (0 == updated_sector) {
        left_start = 0x23;
        right_start = 0x02;
    } else if(11 == updated_sector) {
        left_start = 0x05;
        right_start = 0x02;
    } else {
        left_start = (12 - updated_sector) * 3 - 1;
        right_start = (12 - updated_sector   1) * 3 - 1;
    }
    i2c_write(left_start, pwm_half_value);
    i2c_write(right_start,pwm_half_value);
    i2c_write(0x25, reset_value);
    sys_mdelay(1000);

    printf("left_start = %d, right_start = %dn", left_start, right_start);

    //for debug
    i2c_write(left_start, reset_value);
    i2c_write(right_start, reset_value);
    return 0;
}

int thinking(int sec) {
    blue_backgroud(0);

    while (sec > 0) {
        /*stage 1*/
        for (int i = 0x23; i > 0; i -= 6) {
            i2c_write(i, pwm_half_value);
            i2c_write(0x25, reset_value);
        }
        sys_mdelay(100);
        for (int i = 0x23; i > 0; i -= 6) {
            i2c_write(i, reset_value);
        }
        /*stage 2*/
        for (int i = 0x20; i > 0; i -= 6) {
            i2c_write(i, pwm_half_value);
            i2c_write(0x25, reset_value);
        }
        sys_mdelay(100);
        for (int i = 0x20; i > 0; i -= 6) {
            i2c_write(i, reset_value);
        }
        sec -= 1;
    }
    return 0;
}

int controller_init() {
    //SDB low
    int i;
    //SDB high
    i2c_write(0x4B, config_value);
    for (i = 0x01; i <= 0x24; i  ) {
        i2c_write(i, reset_value);
    }
    for (i = 0x26; i < 0x4A; i  ) {
        i2c_write(i, config_value);
    }
    i2c_write(0x25, reset_value);
    i2c_write(0x00, config_value);
    i2c_write(0x4A, reset_value);
}

int responding() {
    blue_backgroud(0);
    int received = 0;
    int breath_value[22] = {126, 116, 106, 96, 86, 78, 69, 61, 53, 46, 39, 33, 28, 22, 18, 13, 10, 6, 4, 2, 1, 0};
    int step = 15;
    int start = 21;
    while(!received) {
        for (int i = 0x023; i > 0; i -= 3) {
            i2c_write(i, breath_value[start]);
            i2c_write(0x25, reset_value);
        }
        if (start - 1 < 0)
            start = 21;
        else
            start -= 1;
        sys_mdelay(100);
    }
}



int main(int argc, char *argv[]) {
    system("echo 235 > /sys/class/gpio/export");
    system("echo out > /sys/class/gpio/gpio235/direction");
    system("echo 1 > /sys/class/gpio/gpio235/value");
    i2c_init(SLAVE_ADDRESS, 2);
    controller_init();
    responding();

}

0 人点赞