Tuesday, September 28, 2010

Bare Metal: PuppyBeagle i2c driver file to talk to TWL 4030 [i2c.c/i2c.h]

#include "prcm.h"
#include "i2c.h"

void i2c_write (char slaveaddr, char *data, int ploadsz, char stop)
{
i2c_reg *pi2c = (i2c_reg *) I2C1_REG_BASE;

//Config. I2C slave addr. and address count
restart:pi2c->I2C_SA = slaveaddr;
pi2c->I2C_CNT = ploadsz;

pi2c->I2C_DATA = *data;

//Poll for I2C bus free
while (pi2c->I2C_STAT & I2C1_STAT_BB)
;

//Config. I2C to be master and set it to tx mode
pi2c->I2C_CON = I2C1_EN| I2C1_MASTER | I2C1_TX;

  //Initiate transfer (set Start bit only)
pi2c->I2C_CON |= I2C1_CON_STT;
if (stop)
  pi2c->I2C_CON |= I2C1_CON_STP;

//Wait for I2C to be ready again for next request
while (ploadsz)
{
if (pi2c->I2C_STAT & I2C1_STAT_NACK)
{
pi2c->I2C_STAT |= I2C1_STAT_NACK;
goto restart;
}
if (pi2c->I2C_STAT & I2C1_STAT_AL)
{
pi2c->I2C_STAT |= I2C1_STAT_AL;
goto restart;
}
if (pi2c->I2C_STAT & I2C1_STAT_ARDY)
{
pi2c->I2C_STAT |= I2C1_STAT_ARDY;
continue;
}
if (pi2c->I2C_STAT & I2C1_STAT_XRDY)
{
pi2c->I2C_STAT |= I2C1_STAT_XRDY;
data++;
ploadsz--;
  pi2c->I2C_DATA = *data;
}
}

if (!stop)
return;

//Clear status
pi2c->I2C_STAT |= 0xFFFF;
pi2c->I2C_CNT = 0;
}

void i2c_read (char slaveaddr, char *data, int ploadsz, char stop)
{
int resp = 0;
i2c_reg *pi2c = (i2c_reg *) I2C1_REG_BASE;

//Now config. I2C to be master and set it to rx mode to read register
pi2c->I2C_CON = I2C1_EN | I2C1_MASTER | I2C1_RX;

//Initiate receive (set Start and Stop bits set)
pi2c->I2C_CON |= I2C1_CON_STT;

if (stop)
pi2c->I2C_CON |= I2C1_CON_STP;

restart:pi2c->I2C_SA = slaveaddr;
pi2c->I2C_CNT = ploadsz;

pi2c->I2C_DATA = *data;

//Poll for I2C bus free
while (pi2c->I2C_STAT & I2C1_STAT_BB)
;

//Config. I2C to be master and set it to tx mode
pi2c->I2C_CON = I2C1_EN| I2C1_MASTER | I2C1_TX;

  //Initiate transfer (set Start bit only)
pi2c->I2C_CON |= I2C1_CON_STT;
if (stop)
  pi2c->I2C_CON |= I2C1_CON_STP;

//Wait for I2C to be ready again for next request
while (ploadsz)
{
if (pi2c->I2C_STAT & I2C1_STAT_NACK)
{
pi2c->I2C_STAT |= I2C1_STAT_NACK;
goto restart;
}
if (pi2c->I2C_STAT & I2C1_STAT_AL)
{
pi2c->I2C_STAT |= I2C1_STAT_AL;
goto restart;
}
if (pi2c->I2C_STAT & I2C1_STAT_ARDY)
{
pi2c->I2C_STAT |= I2C1_STAT_ARDY;
continue;
}
if (pi2c->I2C_STAT & I2C1_STAT_RRDY)
{
pi2c->I2C_STAT |= I2C1_STAT_RRDY;
data++;
ploadsz--;
  *data = pi2c->I2C_DATA;
}
}

if (!stop)
return;

//Clear status
pi2c->I2C_STAT |= 0xFFFF;
pi2c->I2C_CNT = 0;
 
}

void i2c_reg_read (char slaveaddr, char reg, char value)
{
i2c_reg *pi2c = (i2c_reg *) I2C1_REG_BASE;

i2c_write (slaveaddr, &reg, 1, NO_STOP);
i2c_read (slaveaddr, &value, 1, STOP);

}

void i2c_reg_write (char slaveaddr, char reg, char value)
{
char buf[2];

buf[0] = reg;
buf[1] = value;
i2c_write (slaveaddr, buf, 2, STOP);
}

void i2c_init(void)
{
i2c_reg *pi2c = (i2c_reg *) I2C1_REG_BASE;
corecm_reg *pcorecm = (corecm_reg *) CORECM_REG_BASE;

/*Enable I & F Clocks for I2C1 module */
pcorecm->CORECM_FCLKEN1 |= I2C1_CLOCK_EN;
pcorecm->CORECM_ICLKEN1 |= I2C1_CLOCK_EN;

//Adjust prescalar to obtain 12MHz internal sampling clock
pi2c->I2C_PSC = I2C1_PRESCALAR;

//Config. i2c for a bit rate of 100Kbps

/*
* (TL + TH) * Int_clk = 100 Kbps
* (TL + TH) * 12MHz = 100 Kbps
* 1/(TL + TH) = 120
* Since TL = SCLL + 7 and TH = SCLH + 5, if we choose to have
* TL == TH i.e. both high and low half-cycles to be equal, we
* see that (SCLH + 5) + (SCLL + 7) = 120
* Since TL=TH, the values that satisfy above equation would be
* SCLH = 55 and SCLL = 53
*/

pi2c->I2C_SCLL = I2C1_SCLL_TL;
pi2c->I2C_SCLH = I2C1_SCLL_TH;

//Config. own address (master: 0x1)
pi2c->I2C_OA0 = I2C1_OWN_ADDR;

//Keep TX/RX Threshold at its default values

//We will start with a device reset
if (pi2c->I2C_CON & I2C1_EN)
pi2c->I2C_CON = 0x0;

pi2c->I2C_CON |= I2C1_EN;

//wait for reset complete
while (!(pi2c->I2C_SYSS & I2C_RST_DONE))
;

  i2c_reg_write(I2C1_TWLED_SLAVE_ADDR, LED_REG, LEDB_EN | PWMB_EN);
// i2c_reg_write(I2C1_TWLED_SLAVE_ADDR, LED_REG, LED_EN);

}


And its correspoding header file


#ifndef __I2C_H__
#define __I2C_H__

#define I2C1_REG_BASE 0x48070004

#define I2C1_CLOCK_EN 0x00008000
#define I2C1_PRESCALAR 0x7
#define I2C1_SCLL_TL 0x35
#define I2C1_SCLL_TH 0x37
#define I2C1_OWN_ADDR 0x1
#define I2C1_EN 0x8000
#define I2C1_MASTER 0x400
#define I2C1_TX 0x200
#define I2C1_RX 0x00
#define I2C1_TWLED_SLAVE_ADDR 0x4a
#define I2C1_DCOUNT 0x8
#define I2C1_STAT_BB 0x1000
#define I2C1_CON_STT 0x1
#define I2C1_CON_STP 0x2
#define I2C1_STAT_BB 0x1000
#define I2C1_STAT_XRDY 0x10
#define I2C1_STAT_RRDY 0x8
#define I2C1_STAT_ARDY 0x4
#define I2C1_STAT_NACK 0x2
#define I2C1_STAT_AL 0x0
#define I2C_RESET 0x2
#define I2C_RST_DONE 0x1

#define STOP 1
#define NO_STOP 0

typedef struct {
unsigned short I2C_IE;
unsigned short rsvd1;
unsigned short I2C_STAT;
unsigned short rsvd2;
unsigned short I2C_WE;
unsigned short rsvd3;
unsigned short I2C_SYSS;
unsigned short rsvd4;
unsigned short I2C_BUF;
unsigned short rsvd5;
unsigned short I2C_CNT;
unsigned short rsvd6;
unsigned short I2C_DATA;
unsigned short rsvd7;
unsigned short I2C_SYSC;
unsigned short rsvd8;
unsigned short I2C_CON;
unsigned short rsvd9;
unsigned short I2C_OA0;
unsigned short rsvd10;
unsigned short I2C_SA;
unsigned short rsvd11;
unsigned short I2C_PSC;
unsigned short rsvd12;
unsigned short I2C_SCLL;
unsigned short rsvd13;
unsigned short I2C_SCLH;
unsigned short rsvd14;
unsigned short I2C_SYSTEST;
unsigned short rsvd15;
unsigned short I2C_BUFSTAT;
unsigned short rsvd16;
unsigned short I2C_OA1;
unsigned short rsvd17;
unsigned short I2C_OA2;
unsigned short rsvd18;
unsigned short I2C_OA3;
unsigned short rsvd19;
unsigned short I2C_ACTOA;
unsigned short rsvd20;
unsigned short I2C_SBLOCK;
unsigned short rsvd21;
} i2c_reg;

void i2c_write (char slaveaddr, char *data, int ploadsz, char stop);
void i2c_read (char slaveaddr, char *data, int ploadsz, char stop);

void i2c_reg_write (char slaveaddr, char reg, char value);
void i2c_reg_read (char slaveaddr, char reg, char value);

#define LED_REG 0xEE
#define PWMA_REG 0xEF

#define LEDB_EN 1 << 1
#define PWMB_EN 1 << 5
#define PWMA_ON 63
#define PWMA_OFF 127
#define PWMA_LEN 0x80

#endif

No comments:

Post a Comment