Chinaunix首页 | 论坛 | 博客
  • 博客访问: 396485
  • 博文数量: 380
  • 博客积分: 75
  • 博客等级: 民兵
  • 技术积分: 1925
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-05 15:35
文章分类

全部博文(380)

文章存档

2014年(1)

2013年(2)

2012年(19)

2011年(358)

我的朋友

分类:

2011-09-05 18:29:28

原文地址:U-Boot中的I2C 作者:chenxibing008


以1.3.3的u-boot为例进行介绍。

配置:

在U_Boot中使用I2C需要配置i2c相关,如下是范例:
#define CONFIG_LPC32XX_I2C    1
#define CONFIG_HARD_I2C        1    /* I2C with hardware support    */
#define CONFIG_I2C_CMD_TREE    1
#define CONFIG_CMD_I2C         1
#undef  CONFIG_SOFT_I2C         /* I2C bit-banged        */
#define CFG_I2C_SPEED        100000    /* I2C speed    */

I2C相关命令

配置I2C后在u-boot中将会有如下i2c命令可用:
i2c     - I2C sub-system
icache  - enable or disable instruction cache
icrc32  - checksum calculation
iloop   - infinite loop on address range
imd     - i2c memory display
imm     - i2c memory modify (auto-incrementing)
imw     - memory write (fill)
inm     - memory modify (constant address)
iprobe  - probe to discover valid I2C chip addresses


需要实现的接口:

void i2c_init(int speed, int slaveadd)
int i2c_probe(uchar chip)
int i2c_set_bus_speed(unsigned int speed)
unsigned int i2c_get_bus_speed(void)
int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)

当然,这些接口函数有些可以不用实现,如probe、set/get_speed等,但是init和read/write是必须实现的,否则在编译i2c相关命令的候会有错误提示。

注意,实现i2c的接口,参数必须按照如上的进行传递,否则系统自带的i2c相关命令将不能正常使用。


下面给出LPC3250的i2c接口实现:

#include <common.h>

#ifdef CONFIG_LPC32XX_I2C
#ifdef CONFIG_HARD_I2C

#include <command.h>
#include <i2c.h>        /* Functional interface */

#include <asm/io.h>
//#include     /* HW definitions */

#include <lpc3250.h>
#include "lpc32xx_i2c.h"

#define I2C_READ_BIT 1
#define I2C_WRITE_BIT 0
#define I2C_START_BIT (1<<8)
#define I2C_STOP_BIT (1<<9)

#define WAIT_RESET 0x300000
#define WAIT_TIME 0x300000

DECLARE_GLOBAL_DATA_PTR;

void i2c_reset(void)
{
    int wait = 0;

    while((I2C1->i2c_stat & mstatus_active) != 0) {
        if ((++wait) > WAIT_RESET) {
            printf("%s wait timeout\n", __FUNCTION__);
            break;
        }
    }
    I2C1->i2c_ctrl = (mcntrl_tdie | mcntrl_afie); //0x03


    //reset i2c1 clock
    I2C1->i2c_ctrl = mcntrl_reset;//1<<8;

    wait = 0;
    while((I2C1->i2c_stat & mstatus_rff) != 0) {
        if ((++wait) > WAIT_RESET) {
            printf("%s FAILED\n", __FUNCTION__);
            return 1;
        }
    }
    I2C1->i2c_ctrl = (mcntrl_tdie | mcntrl_afie); //0x03

}

void i2c_init(int speed, int slaveadd)
{
// printf("####ABING in %s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    CLKPWR->clkpwr_i2c_clk_ctrl |= 1; //enable I2C1 clock

    /* Fscl = 100kHz */
    I2C1->i2c_clk_hi = 520;
    I2C1->i2c_clk_lo = 520;

    i2c_reset();
}

int i2c_probe(uchar chip)
{
    printf("####ABING in %s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}

int i2c_set_bus_speed(unsigned int speed)
{
    printf("####ABING in %s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}

unsigned int i2c_get_bus_speed(void)
{
    printf("####ABING in %s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}
#if 0
static int i2c_read_byte (u8 sla, u8 suba, u8 * value)
{
    printf("####ABING in %s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}

static int i2c_write_byte (u8 sla, u8 suba, u8 value)
{
    printf("####ABING in %s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
}
#endif

int i2c_read (uchar sla, uint suba, int alen, uchar *buf, int len)
{
    int wait = 0;
    int stat;
    char data;

    printf("sla = 0x%0x, suba=0x%0x, len=0x%0x\n", sla, suba, len);

    if (suba + len > 256) {
        printf ("I2C read: address out of range\n");
        return 1;
    }
    
    i2c_reset();

    I2C1->i2c_ctrl = 0;
    I2C1->i2c_txrx = ((sla & 0xfe) | I2C_START_BIT | I2C_WRITE_BIT);
    //waiting for transmit OK
    wait = 0;
    while((I2C1->i2c_stat & mstatus_tfe) == 0) {
        if (++wait > WAIT_TIME) {
            i2c_reset();
            return 1;
        }
    }

    I2C1->i2c_txrx = suba;
    //waiting for transmit OK

    wait = 0;
    while((I2C1->i2c_stat & mstatus_tfe) == 0) {
        if (++wait > WAIT_TIME) {
            i2c_reset();
            return 1;
        }
    }

    I2C1->i2c_txrx = ((sla & 0xfe) | I2C_START_BIT | I2C_READ_BIT);
    //waiting for transmit OK
    wait = 0;
    while((I2C1->i2c_stat & mstatus_tfe) == 0) {
        if (++wait > WAIT_TIME) {
            i2c_reset();
            return 1;
        }
    }

    if (len == 1) {
        printf("len=%d\n", len);
        I2C1->i2c_txrx = 0xFF; //write a dummy byte

        //waiting for transmit OK
        wait = 0;
        while((I2C1->i2c_stat & mstatus_tfe) == 0) {
            if (++wait > WAIT_TIME) {
                i2c_reset();
                return 1;
            }
        }

        //waiting for receive data
        wait = 0;
        while((I2C1->i2c_stat & mstatus_rfe) == 1) {
            if (++wait > WAIT_TIME) {
                i2c_reset();
                return 1;
            }
        }

        //put data into buf
        stat= ((I2C1->i2c_stat) & mstatus_rfe);
        //if (((I2C1->i2c_stat) & (1<<9) == 0)) {

        if (stat==0) {
            data = (unsigned char)(I2C1->i2c_txrx);
            *buf++ = data;
   // printf("read1 0x%0x\n", data);
            len--;
        }
    
        I2C1->i2c_txrx = (0xFF | I2C_STOP_BIT);
        //waiting for trasmit OK
        wait = 0;
        while((I2C1->i2c_stat & mstatus_tfe) == 0) {
            if (++wait > WAIT_TIME) {
                i2c_reset();
                return 1;
            }
        }

        //waiting for receive data
        wait = 0;
        while((I2C1->i2c_stat & mstatus_rfe) == 1) {
            if (++wait > WAIT_TIME) {
                break;
            }
        }
        if ((I2C1->i2c_stat & mstatus_rfe) == 0) {
            I2C1->i2c_txrx;
        }

        //waiting until bus is idle
        wait = 0;
        while((I2C1->i2c_stat & mstatus_active) == 1) {
            if (++wait > 2*WAIT_TIME) {
                i2c_reset();
                break;
            }
        }
        //i2c_reset();
        return 0;
    }

    while(len > 0) {
        if (len == 1) {
            I2C1->i2c_txrx = 0xFF | I2C_STOP_BIT;
        } else {
            I2C1->i2c_txrx = 0xFF;
        }

        //waiting for transmit OK
        wait = 0;
        while((I2C1->i2c_stat & mstatus_tfe) == 0) {
            if (++wait > WAIT_TIME) {
                i2c_reset();
                return 1;
            }
        }
    
        //waiting for receive
        wait = 0;
        while((I2C1->i2c_stat & mstatus_rfe) == 1) {
            if (++wait > WAIT_TIME) {
                i2c_reset();
                return 1;
            }
        }

        //put data to buf
        stat = ((I2C1->i2c_stat) & mstatus_rfe);
        //if (I2C1->i2c_stat & mstatus_rfe == 0) {
        if (stat == 0) {
            data = (unsigned char)(I2C1->i2c_txrx);
            *buf++ = data;
            //printf("read2 0x%0x", data);
            len--;
            //printf("len=%d\n", len);
        }

        // waiting until bus is idle
        wait = 0;
        while((I2C1->i2c_stat & mstatus_active) == 1) {
            if (++wait > 2*WAIT_TIME) {
                i2c_reset();
                break;
            }
        }
    }

    //i2c_reset();
    return 0;
}

int i2c_write (uchar sla, uint suba, int alen, uchar *buf, int len)
{
    int wait = 0;
    int stat = 0;

  // printf("####ABING in %s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    //i2c_reset();
    if (suba + len > 256) {
        printf ("I2C read: address out of range\n");
        return 1;
    }
    I2C1->i2c_ctrl = 0;
    I2C1->i2c_txrx=((sla & 0xfe) | I2C_START_BIT | I2C_WRITE_BIT);
    //waiting for transmit OK
    wait = 0;
    while((I2C1->i2c_stat & mstatus_tfe) == 0) {
        if ((++wait) > WAIT_TIME) {
            i2c_reset();
            return 1;
        }
    }

    I2C1->i2c_txrx = suba;
    //waiting for transmit OK
    wait = 0;
    while((I2C1->i2c_stat & mstatus_tfe) == 0) {
        if ((++wait) > WAIT_TIME) {
            i2c_reset();
            return 1;
        }
    }

    while (len > 0)
    {
        if (len == 1) {
            I2C1->i2c_txrx = (*buf | I2C_STOP_BIT);
        } else {
            I2C1->i2c_txrx = *buf;
        }
        //waiting for transmit OK
        wait = 0;
        while((I2C1->i2c_stat & mstatus_tfe) == 0) {
            if ((++wait) > WAIT_TIME) {
                i2c_reset();
                return 1;
            }
        }
        //see if error happen
        stat = (I2C1->i2c_stat & (mstatus_afi | mstatus_nai));
        //if ((I2C1->i2c_stat & (mstatus_afi | mstatus_nai)) != 0) {
        if (stat != 0) {
            printf("write error!\n");
            i2c_reset();
            return 1;
        }
        buf++;
        len--;

        //waiting for transmit OK
        wait = 0;
        while((I2C1->i2c_stat & mstatus_tdi) == 0) {
            if ((++wait) > WAIT_TIME) {
                i2c_reset();
                break;
            }
        }
    }

    return 0;
}

#endif /* CONFIG_HARD_I2C */
#endif /* CONFIG_LPC32XX_I2C */


下面这几行很是费解,直接在if中读取状态寄存器进行判断,即使条件成立,但是括号内的语句却没有执行,后来增加一个stat变量后对变量进行判断,竟然就OK了,很是费解!这个问题竟然搞了很久才发现,fuck!估计是编译器的问题,反正已经实现了,也就不深究了,如果哪位仁兄知道的话,麻烦告知一声,tks。
        stat = (I2C1->i2c_stat & (mstatus_afi | mstatus_nai));
        //if ((I2C1->i2c_stat & (mstatus_afi | mstatus_nai)) != 0) {
        if (stat != 0) {

阅读(580) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~