海思uboot阶段模拟i2c

该代码实现了一个Linux环境下使用GPIO模拟I2C通信的程序。通过修改GPIO寄存器地址和位移来控制SCL和SDA线的状态,实现了I2C的开始、停止、发送数据和接收数据等操作。代码中区分了FPGA和非FPGA两种情况,分别定义了不同的GPIO基地址和位移。此外,还包含了延迟函数以满足I2C时序要求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

理论所有linux都可以使用。在文件i2c_hibvt.c改为。下面的代码主要修改GPIO_15_BASE SCL_SHIFT_NUM,修改makefile kconfig保证代码被编译


#include <linux/errno.h>

 
#include "i2c_hibvt.h"
#define demo_delay time_delay_us(2)
#ifdef HI_FPGA
 
#define GPIO_15_BASE 0x12240000
#define SCL_SHIFT_NUM 2
#define SDA_SHIFT_NUM 3
#define SCL (0x1 << SCL_SHIFT_NUM)                                                                                   /* GPIO7 0_7 */
#define SDA (0x1 << SDA_SHIFT_NUM)                                                                                   /* GPIO7 0_6 */
#define GPIO_I2C_SCL_REG IO_ADDRESS(GPIO_15_BASE + (0x1 << (SCL_SHIFT_NUM + 2)))                                     /* 0x200 */
#define GPIO_I2C_SDA_REG IO_ADDRESS(GPIO_15_BASE + (0x1 << (SDA_SHIFT_NUM + 2)))                                     /* 0x100 */
#define GPIO_I2C_SCLSDA_REG IO_ADDRESS(GPIO_15_BASE + ((0x1 << (SCL_SHIFT_NUM + 2)) + (0x1 << (SDA_SHIFT_NUM + 2)))) /* 0x300 need check */
 
#else
/*记得修改Makefile里面的路径*/
/*下面需要修改为对应芯片的*/
#define GPIO_15_BASE 0x120b1000 
#define SCL_SHIFT_NUM 4
#define SDA_SHIFT_NUM 5
/*上面需要修改为对应芯片的*/
 
 
#define SCL (0x1 << SCL_SHIFT_NUM)                                                                                   /* GPIO1 0_7 */
#define SDA (0x1 << SDA_SHIFT_NUM)                                                                                   /* GPIO1 0_6 */
void  * GPIO_I2C_SCL_REG; 
void  * GPIO_I2C_SDA_REG;
void  * GPIO_I2C_SCLSDA_REG; /* 0x300 need check */
 
#endif
 
void  *GPIO_0_DIR; 
#define HW_REG(reg) *((volatile unsigned int *)(reg))
#define DELAY(us) time_delay_us(us)
 
/* 
 * I2C by GPIO simulated  clear 0 routine.
 *
 * @param whichline: GPIO control line
 *
 */
static void i2c_clr(unsigned char whichline)
{
    unsigned char regvalue;
 
    if (whichline == SCL)
    {
        regvalue = HW_REG(GPIO_0_DIR);
        regvalue |= SCL;
        HW_REG(GPIO_0_DIR) = regvalue;
 
        HW_REG(GPIO_I2C_SCL_REG) = 0;
        return;
    }
    else if (whichline == SDA)
    {
        regvalue = HW_REG(GPIO_0_DIR);
        regvalue |= SDA;
        HW_REG(GPIO_0_DIR) = regvalue;
 
        HW_REG(GPIO_I2C_SDA_REG) = 0;
        return;
    }
    else if (whichline == (SDA | SCL))
    {
        regvalue = HW_REG(GPIO_0_DIR);
        regvalue |= (SDA | SCL);
        HW_REG(GPIO_0_DIR) = regvalue;
 
        HW_REG(GPIO_I2C_SCLSDA_REG) = 0;
        return;
    }
    else
    {
        printk("Error input.\n");
        return;
    }
}
 
 
/*
 *  delays for a specified number of micro seconds rountine.
 *
 *  @param usec: number of micro seconds to pause for
 *
 */
void time_delay_us(unsigned int usec)
{
    //	volatile int i,j;
 
#ifdef HI_FPGA
    for (i = 0; i < usec * 5; i++)
    {
        for (j = 0; j < 47; j++)
        {
            ;
        }
    }
#else
    udelay(usec * 60);
 
#endif
}
/* 
 * I2C by GPIO simulated  set 1 routine.
 *
 * @param whichline: GPIO control line
 *
 */
static void i2c_set(unsigned char whichline)
{
    unsigned char regvalue;
 
    if (whichline == SCL)
    {
        regvalue = HW_REG(GPIO_0_DIR);
        regvalue |= SCL;
        HW_REG(GPIO_0_DIR) = regvalue;
 
        HW_REG(GPIO_I2C_SCL_REG) = SCL;
        return;
    }
    else if (whichline == SDA)
    {
        regvalue = HW_REG(GPIO_0_DIR);
        regvalue |= SDA;
        HW_REG(GPIO_0_DIR) = regvalue;
 
        HW_REG(GPIO_I2C_SDA_REG) = SDA;
        return;
    }
    else if (whichline == (SDA | SCL))
    {
        regvalue = HW_REG(GPIO_0_DIR);
        regvalue |= (SDA | SCL);
        HW_REG(GPIO_0_DIR) = regvalue;
 
        HW_REG(GPIO_I2C_SCLSDA_REG) = (SDA | SCL);
        return;
    }
    else
    {
        printk("Error input.\n");
        return;
    }
}
 
/* 
 * I2C by GPIO simulated  read data routine.
 *
 * @return value: a bit for read 
 *
 */
 
static unsigned char i2c_data_read(void)
{
    unsigned char regvalue;
 
    regvalue = HW_REG(GPIO_0_DIR);
    regvalue &= (~SDA);
    HW_REG(GPIO_0_DIR) = regvalue;
    DELAY(1);
 
    regvalue = HW_REG(GPIO_I2C_SDA_REG);
    if ((regvalue & SDA) != 0)
        return 1;
    else
        return 0;
}
 
static void demo_i2c_start(void)
{
    // //out_scl();
    // //out_sda();
 
    high_scl;
 
    high_sda;
    demo_delay;
    low_sda;
    demo_delay;
 
    low_scl;
}
 
static void demo_i2c_stop(void)
{
    //out_scl();
    //out_sda();
 
    high_scl;
 
    low_sda;
    demo_delay;
    high_sda;
    demo_delay;
 
    low_scl;
}
 
/*
 * sends a character over I2C rountine.
 *
 * @param  c: character to send
 *
 */
static void demo_i2c_send_byte(unsigned char data)
{
    int i = 0;
    //out_scl();
    //out_sda();
 
    low_scl;
    for(i=0;i<8;i++) {
        if(data & (0x80>>i))
            high_sda;
        else
            low_sda;
        demo_delay;
        high_scl;
        demo_delay;
        low_scl;
    }
}
 
/*  receives a character from I2C rountine.
 *
 *  @return value: character received
 *
 */
static unsigned char demo_i2c_recv_byte(void)
{
    int i = 0;
    unsigned char data = 0;
    //out_scl();
    //in_sda();
 
    low_scl;
    for(i=0;i<8;i++) {
        demo_delay;
        high_scl;
        demo_delay;
        data <<= 1;//循环8次,最终只左移了7次
        data |= i2c_data_read();
        low_scl;
    }
    return data;
}
 
 
/*  receives an acknowledge from I2C rountine.
 *
 *  @return value: 0--Ack received; 1--Nack received
 *          
 */
static unsigned char demo_i2c_recv_ack(void)
{
    int nack;
    unsigned char regvalue;
    regvalue = HW_REG(GPIO_0_DIR);
    regvalue &= (~SDA);
    HW_REG(GPIO_0_DIR) = regvalue;
 
    //DELAY(1);
    i2c_clr(SCL);
    DELAY(1);
    i2c_set(SCL);
    DELAY(1);
 
    nack = i2c_data_read();
 
    DELAY(1);
    i2c_clr(SCL);
    DELAY(1);
 
    if (nack == 0)
    {
        return 0;
    }
    else
    {
        return 1;
    }
}
 
 
static void demo_i2c_send_ack(unsigned char ack)
{
    //out_scl();
    //out_sda();
    low_scl;
    if(ack)
        high_sda;
    else
        low_sda;
    demo_delay;
    high_scl;
    demo_delay;
    low_scl;
}
 
 
EXPORT_SYMBOL(gpio_i2c_read);
unsigned char gpio_i2c_read(unsigned char devaddress, unsigned char address)
{
    int i = 0,len=1;
    char buff;
 
    demo_i2c_start();
    demo_i2c_send_byte((unsigned char)(devaddress));
    if(demo_i2c_recv_ack()) {
        printk("data:0x%02x\n",(unsigned char)(devaddress));
        printf( "%d,get a nack.\n", __LINE__);
        return -1;
    }
    demo_i2c_send_byte(address & 0xff);
    if(demo_i2c_recv_ack()) {
        printk("address:0x%02x\n",address & 0xff);
        printf( "%d,get a nack.\n", __LINE__);
        return -1;
    }
 
    demo_i2c_start();
    demo_i2c_send_byte((unsigned char)(devaddress) | 1);
    if(demo_i2c_recv_ack()) {
        printk("devaddress:0x%02x\n",(unsigned char)(devaddress) | 1);
        printf( "%d,get a nack.\n", __LINE__);
        return -1;
    }
 
    for(i=0; i<(len-1); i++) {
        buff = demo_i2c_recv_byte();
        demo_i2c_send_ack(0);
    }
    buff = demo_i2c_recv_byte();
    demo_i2c_send_ack(1);
 
    demo_i2c_stop();
    return buff;
}
 
EXPORT_SYMBOL(gpio_i2c_write);
void gpio_i2c_write(unsigned char devaddress, unsigned int address, unsigned char data)
{
   int i = 0,len=1;
 
    demo_i2c_start();
    demo_i2c_send_byte((unsigned char)(devaddress));
    if(demo_i2c_recv_ack()) {
        printf( "%d,get a nack.\n", __LINE__);
        return -1;
    }
    demo_i2c_send_byte(address & 0xff);
    if(demo_i2c_recv_ack()) {
        printf( "%d,get a nack.\n", __LINE__);
        return -1;
    }
    for(i=0; i<len; i++) {
        demo_i2c_send_byte(data);
        if(demo_i2c_recv_ack()) {
            printf( "%d,get a nack.\n", __LINE__);
            return -1;
        }
    }
 
    demo_i2c_stop();
    return i;
}
 
#if 0
long gpioi2c_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int ret;
    unsigned char device_addr;
    unsigned int reg_addr;
    unsigned int reg_val;
    GPIOI2C_DATA_S i2c_data_t;
 
    switch (cmd)
    {
    case GPIO_I2C_READ:
         ret=copy_from_user(&i2c_data_t, (GPIOI2C_DATA_S *)arg, sizeof(GPIOI2C_DATA_S));
        device_addr = i2c_data_t.dev_addr;
        reg_addr = i2c_data_t.reg_addr;
        i2c_data_t.data = gpio_i2c_read(device_addr, reg_addr);
        printk("GPIO_I2C_READ--device_addr:0x%02x  reg_addr:0x%02x  reg_val:0x%02x\n", device_addr, reg_addr,  i2c_data_t.data);
        ret=copy_to_user((GPIOI2C_DATA_S *)arg, &i2c_data_t, sizeof(GPIOI2C_DATA_S));
        break;
 
    case GPIO_I2C_SELCHN:
 
        break;
 
    case GPIO_I2C_WRITE:
        ret=copy_from_user(&i2c_data_t, (GPIOI2C_DATA_S *)arg, sizeof(GPIOI2C_DATA_S));
        device_addr = i2c_data_t.dev_addr;
        reg_addr = i2c_data_t.reg_addr;
        reg_val = i2c_data_t.data;
        gpio_i2c_write(device_addr, reg_addr, reg_val);
        break;
    case GPIO_I2C_WRITE2:
        ret=copy_from_user(&i2c_data_t, (GPIOI2C_DATA_S *)arg, sizeof(GPIOI2C_DATA_S));
        break;
    case GPIO_I2C_WRITE4:
        ret=copy_from_user(&i2c_data_t, (GPIOI2C_DATA_S *)arg, sizeof(GPIOI2C_DATA_S));
        break;
 
    default:
        printk("error!!%d\n", cmd);
        return -1;
    }
    return 0;
}
#endif
int gpioi2c_open(struct inode *inode, struct file *file)
{
    return 0;
}
int gpioi2c_close(struct inode *inode, struct file *file)
{
    return 0;
}
 

 
int  gpio_i2c_init(void)
{
    int ret;
    //unsigned int reg;
    GPIO_0_DIR=ioremap(GPIO_15_BASE + 0x400, 1); /* GPIO direction reg */
    GPIO_I2C_SCL_REG=ioremap(GPIO_15_BASE + (0x1 << (SCL_SHIFT_NUM + 2)), 1);                                     /* 0x200 */
    GPIO_I2C_SDA_REG=ioremap(GPIO_15_BASE + (0x1 << (SDA_SHIFT_NUM + 2)), 1);      
    GPIO_I2C_SCLSDA_REG=ioremap(GPIO_15_BASE + ((0x1 << (SCL_SHIFT_NUM + 2)) + (0x1 << (SDA_SHIFT_NUM + 2))), 1); 

    return 0;
}
 
void gpio_i2c_exit(void)
{
    iounmap(GPIO_0_DIR); /* GPIO direction reg */
    iounmap(GPIO_I2C_SCL_REG);                                     /* 0x200 */
    iounmap(GPIO_I2C_SDA_REG);      
    iounmap(GPIO_I2C_SCLSDA_REG); 
}
 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值