minilogic / f1c_nonos

Bare metal code examples for Allwinner's F1C100S (F1C200S) SOC
71 stars 27 forks source link

How to use I2C ? #4

Closed zare-hamid closed 5 months ago

zare-hamid commented 9 months ago

Hello. I want to use touch gt911. But I can't activate i2c.

satar1980 commented 8 months ago

you can try this code ii.c

include

include "iic.h"

enum { I2C_ADDR = 0x000, I2C_XADDR = 0x004, I2C_DATA = 0x008, I2C_CNTR = 0x00c, I2C_STAT = 0x010, I2C_CCR = 0x014, I2C_SRST = 0x018, I2C_EFR = 0x01c, I2C_LCR = 0x020, };

enum { I2C_STAT_BUS_ERROR = 0x00, I2C_STAT_TX_START = 0x08, I2C_STAT_TX_RSTART = 0x10, I2C_STAT_TX_AW_ACK = 0x18, I2C_STAT_TX_AW_NAK = 0x20, I2C_STAT_TXD_ACK = 0x28, I2C_STAT_TXD_NAK = 0x30, I2C_STAT_LOST_ARB = 0x38, I2C_STAT_TX_AR_ACK = 0x40, I2C_STAT_TX_AR_NAK = 0x48, I2C_STAT_RXD_ACK = 0x50, I2C_STAT_RXD_NAK = 0x58, I2C_STAT_IDLE = 0xf8, };

struct i2c_f1c100s_pdata_t { unsigned int virt; };

struct i2c_f1c100s_pdata_t i2c_Data;

static i2c_delay(int us) { volatile int i; while(us--) { for(i = 0;i< 600;i++) { ; } } }

static void f1c100s_i2c_set_rate(struct i2c_f1c100s_pdata_t pdat, unsigned long long rate) { // u64_t pclk = clk_f1c100s_pll_chanel_get_rate(5,24000000);//clk_get_rate(pdat->clk); // i2c_printf("i2c_src_clock get %d Hz\n",pclk); // s64_t freq, delta, best = 0x7fffffffffffffffLL; // int tm = 5, tn = 0; // int m, n; // // for(n = 0; n <= 7; n++) // { // for(m = 0; m <= 15; m++) // { // freq = pclk / (10 (m + 1) (1 << n)); // delta = rate - freq; // if(delta >= 0 && delta < best) // { // tm = m; // tn = n; // best = delta; // } // if(best == 0) // break; // } // } int tm = 2, tn = 2; // from datasheet 400khz //i2c_printf("I2C_CCR bit3:%d ,bit0:%d\n",tm,tn); i2c_write32(pdat->virt + I2C_CCR, ((tm & 0xf) << 3) | ((tn & 0x7) << 0)); } static int f1c100s_i2c_wait_status(struct i2c_f1c100s_pdata_t pdat) { //ktime_t timeout = ktime_add_ms(ktime_get(), 1);

unsigned int timeout = 1000;
do {
    if((i2c_read32(pdat->virt + I2C_CNTR) & (1 << 3)))
        return i2c_read32(pdat->virt + I2C_STAT);
   // delay_us(1);
} while(--timeout);
return I2C_STAT_BUS_ERROR;

}

static int f1c100s_i2c_start(struct i2c_f1c100s_pdata_t * pdat) { i2c_write32(pdat->virt + I2C_CNTR, (1 << 7) | (1 << 6) | (1 << 5) | (1 << 2));

//ktime_t timeout = ktime_add_ms(ktime_get(), 1);
unsigned int timeout = 1000;
do {
    if(!(i2c_read32(pdat->virt + I2C_CNTR) & (1 << 5)))
        break;
    //i2c_delay(10);
} while(--timeout);
if(!timeout)
{
    LCD_printf("f1c100s_i2c_start time out \n");
}
return f1c100s_i2c_wait_status(pdat);

}

static int f1c100s_i2c_stop(struct i2c_f1c100s_pdata_t * pdat) { i2c_write32(pdat->virt + I2C_CNTR, (i2c_read32(pdat->virt + I2C_CNTR) | (1 << 4)) & ~((1 << 7) | (1 << 3))); //ktime_t timeout = ktime_add_ms(ktime_get(), 1); unsigned int timeout = 1000; do { if(!(i2c_read32(pdat->virt + I2C_CNTR) & (1 << 4))) return 0; // i2c_delay(10); } while(--timeout); return -1; }

static int f1c100s_i2c_send_data(struct i2c_f1c100s_pdata_t * pdat, unsigned char dat) { i2c_write32(pdat->virt + I2C_DATA, dat); i2c_write32(pdat->virt + I2C_CNTR, i2c_read32(pdat->virt + I2C_CNTR) & (~(1 << 3))); return f1c100s_i2c_wait_status(pdat); }

static int f1c100s_i2c_read(struct i2c_f1c100s_pdata_t pdat, struct i2c_msg_t msg) { unsigned char * p = msg->buf; int len = msg->len;

if(f1c100s_i2c_send_data(pdat, (unsigned char)(msg->addr << 1 | 1)) != I2C_STAT_TX_AR_ACK)
    return -1;

while(len > 0)
{
    switch(f1c100s_i2c_wait_status(pdat))
    {
        case I2C_STAT_TX_AR_ACK:
            if(len == 1)
                i2c_write32(pdat->virt + I2C_CNTR, i2c_read32(pdat->virt + I2C_CNTR) & ~((1 << 3) | (1 << 2)));
            else
                i2c_write32(pdat->virt + I2C_CNTR, i2c_read32(pdat->virt + I2C_CNTR) & ~(1 << 3));
            break;
        case I2C_STAT_RXD_ACK:
            *p++ = i2c_read32(pdat->virt + I2C_DATA);
            len--;
            if(len == 1)
                i2c_write32(pdat->virt + I2C_CNTR, i2c_read32(pdat->virt + I2C_CNTR) & ~((1 << 3) | (1 << 2)));
            else
                i2c_write32(pdat->virt + I2C_CNTR, i2c_read32(pdat->virt + I2C_CNTR) & ~(1 << 3));
            break;
        case I2C_STAT_RXD_NAK:
            *p++ = i2c_read32(pdat->virt + I2C_DATA);
            len--;
            break;
        default:
            return -1;
    }
}
return 0;

}

static int f1c100s_i2c_write(struct i2c_f1c100s_pdata_t pdat, struct i2c_msg_t msg) { unsigned char p = msg->buf; int len = msg->len; if(f1c100s_i2c_send_data(pdat, (unsigned char)(msg->addr << 1)) != I2C_STAT_TX_AW_ACK) { // LCD_printf("f1c100s_i2c_write data failed\n"); return -1; } while(len > 0) { if(f1c100s_i2c_send_data(pdat, p++) != I2C_STAT_TXD_ACK) { // LCD_printf("!= I2C_STAT_TXD_ACK\n"); return -1; } len--; } return 0; }

static int i2c_f1c100s_xfer(struct i2c_msg_t msgs, int num) { struct i2c_f1c100s_pdata_t pdat = &i2c_Data; struct i2c_msg_t * pmsg = msgs; int i, res;

if(!msgs || num <= 0)
    return 0;

if(f1c100s_i2c_start(pdat) != I2C_STAT_TX_START)
    return 0;

for(i = 0; i < num; i++, pmsg++)
{
    if(i != 0)
    {
        if(f1c100s_i2c_start(pdat) != I2C_STAT_TX_RSTART)
            break;
    }
    if(pmsg->flags & I2C_M_RD)
        res = f1c100s_i2c_read(pdat, pmsg);
    else
        res = f1c100s_i2c_write(pdat, pmsg);
    if(res < 0)
        break;
}
f1c100s_i2c_stop(pdat);

return i;

}

unsigned char i2c_reg_read(int ch,unsigned char addr,unsigned char reg ) { struct i2c_f1c100s_pdata_t pdat = &i2c_Data; struct i2c_msg_t i2c_msg; unsigned char dat; int ret = -1; dat = reg; i2c_msg.addr = addr; i2c_msg.buf = &dat; i2c_msg.len = 1; if(f1c100s_i2c_start(pdat) != I2C_STAT_TX_START) { // LCD_printf("f1c100s_i2c_start(pdat) != I2C_STAT_TX_START \n"); return 0; } if(f1c100s_i2c_write(pdat, &i2c_msg)) { f1c100s_i2c_stop(pdat); return 0; } dat = 0; if(f1c100s_i2c_start(pdat) != I2C_STAT_TX_RSTART) { f1c100s_i2c_stop(pdat); return 0; } if(f1c100s_i2c_read(pdat, &i2c_msg)) { f1c100s_i2c_stop(pdat); return 0; } f1c100s_i2c_stop(pdat); return dat; } int i2c_reg_write(int ch,unsigned char addr,unsigned char reg ,unsigned char wdat) { struct i2c_f1c100s_pdata_t pdat = &i2c_Data; struct i2c_msg_t i2c_msg; unsigned char dat[4]; int ret = -1; dat[0] = reg; dat[1] = wdat; i2c_msg.addr = addr; i2c_msg.buf = &dat[0]; i2c_msg.len = 2; if(f1c100s_i2c_start(pdat) != I2C_STAT_TX_START) { return -3; } if(f1c100s_i2c_write(pdat, &i2c_msg)) { f1c100s_i2c_stop(pdat); return -2; } f1c100s_i2c_stop(pdat); ret = 0; return ret; }

void i2c_open_clock(int ch) { // LCD_printf("i2c_open_clock for i2c%d\n",ch); switch(ch) { case 0: i2c_set_bit(BUS_CLK_GATING_REG2,1 << TWI0_CLK_GATE_BIT); i2c_set_bit(BUS_SOFT_RST_REG2,1 << TWI0_CLK_RST_BIT); break; case 1: i2c_set_bit(BUS_CLK_GATING_REG2,1<<TWI1_CLK_GATE_BIT); i2c_set_bit(BUS_SOFT_RST_REG2,1<<TWI1_CLK_RST_BIT); break; case 2: i2c_set_bit(BUS_CLK_GATING_REG2,1<<TWI2_CLK_GATE_BIT); i2c_set_bit(BUS_SOFT_RST_REG2,1<<TWI2_CLK_RST_BIT); break; default: break; }

}

int i2c_f1c100s_init(int ch) { struct i2c_f1c100s_pdata_t * pdat = &i2c_Data;

// i2c_gpio_stu i2c_gpio[3]={ // {GPIOE, 12, GPIOE, 11, GPIO_MODE_AF3, GPIO_PULL_NONE}, // {GPIOD, 6, GPIOD, 5, GPIO_MODE_AF3, GPIO_PULL_NONE}, // {GPIOE, 1, GPIOE, 0, GPIO_MODE_AF4, GPIO_PULL_NONE} // };

unsigned int virt = I2C0_BASE_ADDR + ch * 0x400 ;

pdat->virt = virt;

// LCD_printf("init gpio for i2c%d\n",ch);

gpio_pin_init(GPIOE, 1, GPIO_MODE_AF4, GPIO_PULL_NONE, 2); //SDA
gpio_pin_init(GPIOE, 0, GPIO_MODE_AF4, GPIO_PULL_NONE, 2);

i2c_open_clock(ch);

i2c_write32(pdat->virt + I2C_SRST, 1 << 0);
i2c_write32(pdat->virt + I2C_SRST, 0 << 0);
f1c100s_i2c_set_rate(pdat, 400000);

i2c_write32(pdat->virt + I2C_ADDR, 0);
i2c_write32(pdat->virt + I2C_XADDR, 0);
i2c_write32(pdat->virt + I2C_CNTR, (1 << 6) | (1 << 4));

return 0;

}

satar1980 commented 8 months ago

iic.h

ifndef _DRV_I2CH

define _DRV_I2CH

enum { I2C_M_TEN = 0x0010, I2C_M_RD = 0x0001, I2C_M_STOP = 0x8000, I2C_M_NOSTART = 0x4000, I2C_M_REV_DIR_ADDR = 0x2000, I2C_M_IGNORE_NAK = 0x1000, I2C_M_NO_RD_ACK = 0x0800, I2C_M_RECV_LEN = 0x0400, };

struct i2c_msg_t { int addr; int flags; int len; void * buf; };

define I2C0_BASE_ADDR 0x01c27000

define I2C1_BASE_ADDR 0x01c27400

define I2C2_BASE_ADDR 0x01c27800

define i2c_read32(reg) ((volatile unsigned long )(reg))

define i2c_write32(reg, value) ((volatile unsigned long )(reg) = (value))

define i2c_set_bit(reg, bp) (i2c_write32((reg),(i2c_read32(reg) | ((bp))) ))

define i2c_clr_bit(reg, bp) (i2c_write32((reg),(i2c_read32(reg) & (~ ((bp)))) ))

define F1C100S_CLK_BASE 0x01C20000

define BUS_CLK_GATING_REG2 (F1C100S_CLK_BASE+0x068)

define TWI0_CLK_GATE_BIT 16

define TWI1_CLK_GATE_BIT 17

define TWI2_CLK_GATE_BIT 18

define BUS_SOFT_RST_REG2 (F1C100S_CLK_BASE+0x2d0)

define TWI0_CLK_RST_BIT 16

define TWI1_CLK_RST_BIT 17

define TWI2_CLK_RST_BIT 18

int i2c_reg_write(int ch,unsigned char addr,unsigned char reg ,unsigned char wdat); unsigned char i2c_reg_read(int ch,unsigned char addr,unsigned char reg );

endif / _DRV_I2CH /

minilogic commented 8 months ago

I2C examples