4412裸机程序之IIC

来源:互联网 发布:艾科特餐饮软件 编辑:程序博客网 时间:2024/05/16 14:25
IIC总线是个比较重要的模块,很多外设都通过IIC来传输数据,下面大致说下IIC总线协议原理:





IIC只有2条线,SDA(数据线)/SCL(时钟线),分为主机(IIC控制器)和从机(EEPROM),2条线上可以挂很多从机设备,主机通过向从机发地址,哪个从机响应了,就与哪个从机通信。
当SCL/SDA都为高电平时,拉低SDA作为起始信号,  SCL为高,拉高SDA做为结束信号,从机在收到8位数据后,在第9个时钟周期拉底SDA作为ACK应答信号。
scl为低时可以传送数据,传送完后SCL会被拉高,在scl上升沿开始传数据。scl为高时要保持sda数据稳定。
发送完数据,读完数据,发送完stop信号,都要delay一会,等设备反应。
传送数据按芯片手册的timing走,先传地址,先传数据,每传一个8位数据,从机要发送一个ACK应答。
我们编程是以主机的角色,从机自己会拉高拉底scl/sda,主机也不用管怎么拉高拉低SCL/SDA,只需设置IIC控制器的寄存器就可以按timing传数据。
Tiny4412有一个直接连接CPU IIC0 信号引脚的EEPROM芯片AT24C08,主要是为了测试IIC总线用,我们看下往这个设备读写数据应该怎么操作。
下图是写数据时的流程:


首先发start信号,然后写从机的8位设备地址(可以从AT24C08的手册找到),最后1位用来标识接下来是要写还是读从机设备。从机收到地址后如果跟自己地址匹配,就发一个ACK应答给主机。
从机里的数据是按addr来index的,要那块地址写数据,先发addr给从机,从机准备好后发ACK,然后主机就发8位data给从机,从机应答,然后主机发stop信号结束。
读的流程类似如下:


发start信号,发从机地址,最后1位标识write, 发要读哪块地址数据的addr,重新发start信号,发从机地址,最后1位标识read, 然后读数据,读完数据从机一般不会应答(no ack),主机发stop信号结束。
代码中断控制的流程说明如下:
当收到中断时I2c会停止传数据,在write时,当rIICDS = _iicData[_iicPt++]时可以假设数据还没发送出去,启动i2c,发送完会触发中断,在中断里我们继续write或结束,从机有没发ACK可以读寄存器。
在read时,当_iicData[_iicPt++] = rIICDS时可以假设数据还没读到,启动i2c,读完数据后会触发中断,在中断里我们继续read或结束,read时一般读最后一个数据后从机不会发ack, 要在读最后一个数据之前设置con不收ack
//IIC
#define iic_base 0x13860000
#define I2CCON0 (*(volatile unsigned int *)(iic_base+0x0000))
#define I2CSTAT0 (*(volatile unsigned int *)(iic_base+0x0004))
#define I2CADD0 (*(volatile unsigned int *)(iic_base+0x0008))
#define I2CDS0 (*(volatile unsigned int *)(iic_base+0x000C))
#define I2CLC0 (*(volatile unsigned int *)(iic_base+0x0010))
#define GPD1CON (*(volatile unsigned int *)0x114000C0)
#define GPD1PUD (*(volatile unsigned int *)0x114000C8)

void (*uart_asm_putc)(int c) = 0x02023918;
void (*uart_asm_putx)(int x) = 0x0202393c;

void udelay(volatile int u)
{

volatile int i,j;
for(j=0;j<u;j++)
{ for(i=0 ; i < 1000 ; i++) { } }

}

void printf(char *str)
{
    while (*str)
    {
     uart_asm_putc(*str);
         str++;
    }
}

void iic_init()
{
  GPD1CON &= ~(0xff);
  GPD1CON |= (0x22);
  GPD1PUD = 0;

  I2CCON0 = 0x1 | (1 << 5) | (1 << 6);
  //I2CADD0 = 0xc0;
  I2CSTAT0 = 0x10;
  I2CLC0 = 7;
}

void iic_dest(void)
{
  I2CCON0 = 0;
  I2CSTAT0 = 0;
}

void iic_master_write(unsigned long slave_addr, unsigned long reg, char val)
{
  char data[2];
  int cnt = 2;

  data[0] = reg;
  data[1] = val;

  while(I2CSTAT0 & (1 << 5));

  I2CCON0 |= (1 << 7);
  I2CDS0 = slave_addr;
  I2CSTAT0 = 0xf0;
  udelay(10);

  int pt = 0;
  while(cnt >= 0) {
       if (I2CCON0 & 0x10) {
        if (0 == cnt)
            break;

        cnt--;
        I2CDS0 = data[pt++];
        udelay(1);
        I2CCON0 &= ~(1 << 4);
    }
  }

  I2CSTAT0 = 0xd0;
  I2CCON0 &= ~(1 << 4);
  udelay(10);

}

void iic_master_read(unsigned long slave_addr, unsigned long reg, unsigned char* val)
{
  int cnt = 1;

  while(I2CSTAT0 & (1 << 5));

  udelay(10);
  I2CCON0 |= (1 << 7);
  I2CDS0 = slave_addr;
  I2CSTAT0 = 0xf0;
  udelay(10);

  while(cnt >= 0) {
       if (I2CCON0 & 0x10) {
        if ((cnt--) == 0)
            break;

        I2CDS0 = reg;
        udelay(1);
        I2CCON0 &= ~(1 << 4);
    }
  }

  I2CSTAT0 = 0xd0;
  I2CCON0 &= ~(1 << 4);
  udelay(10);

  //-------------------read
  char data[3];
  while(I2CSTAT0 & (1 << 5));
  udelay(10);
  I2CCON0 |= (1 << 7);
  udelay(10);
  I2CDS0 = slave_addr;
  I2CSTAT0 = 0xb0;
  udelay(10);

  cnt = 0;
  while (cnt < 3) {
    if (I2CCON0 & 0x10) {
        data[cnt] = I2CDS0;
         cnt++;

        I2CCON0 &= ~(1 << 4);
        udelay(10);
    }
  }
  I2CSTAT0 = 0x90;
  udelay(10);
  *val = data[1];
}

int main(void)
{
char rec;
unsigned char value = 0;

printf("\n\r\n\r");

iic_init();

printf("\n\r");
iic_master_write(0xa0, 0x3, 0x15);
iic_master_read(0xa0, 0x3, &value);
printf("addr 0x3 value is: ");
uart_asm_putx(value);
printf("\n\r");

iic_dest();
 
return 0;
}

代码位置:https://github.com/cyj1988jyc/luoji4412/tree/master/ddr_IIC
0 0
原创粉丝点击