前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >全志平台Tina系统led控制芯片is31fl3236调试(以R18 linux4.4内核为例)

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

作者头像
阿志小管家
发布2024-02-02 14:58:02
820
发布2024-02-02 14:58:02
举报

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> %02X", led_bChipAddress<<1);
        for(i=0;i<msg[0].len ;i++)
        {
            printf(" %02X",(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 %s\n",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 = %d\n", (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 = %d\n", 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 = %d\n", 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();

}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-02-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档