iic.c
351 lines
| 10.8 KiB
| text/x-c
|
CLexer
r6 | /*------------------------------------------------------------------------------ | |||
-- This file is a part of the libuc, microcontroler library | ||||
-- Copyright (C) 2011, Alexis Jeandet | ||||
-- | ||||
-- This program is free software; you can redistribute it and/or modify | ||||
-- it under the terms of the GNU General Public License as published by | ||||
-- the Free Software Foundation; either version 3 of the License, or | ||||
-- (at your option) any later version. | ||||
-- | ||||
-- This program is distributed in the hope that it will be useful, | ||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
-- GNU General Public License for more details. | ||||
-- | ||||
-- You should have received a copy of the GNU General Public License | ||||
-- along with this program; if not, write to the Free Software | ||||
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
------------------------------------------------------------------------------- | ||||
-- Author : Alexis Jeandet | ||||
-- Mail : alexis.jeandet@gmail.com | ||||
-------------------------------------------------------------------------------*/ | ||||
#include "iic.h" | ||||
#include "core.h" | ||||
r10 | #define iicputdata(iicdev,W,IICONSET,IICONCLR) {(iicdev)->I2DAT = (W);\ | |||
r6 | (iicdev)->I2CONSET = (IICONSET);\ | |||
r10 | (iicdev)->I2CONCLR = (IICONCLR);} | |||
r6 | ||||
r10 | #define iicgetdata(iicdev,W,IICONSET,IICONCLR) {(W) = (iicdev)->I2DAT;\ | |||
r6 | (iicdev)->I2CONSET = (IICONSET);\ | |||
r10 | (iicdev)->I2CONCLR = (IICONCLR);} | |||
r6 | ||||
i2ctrl i2cwrite2(i2cDev* dev,char address,char*cmd,int* cmdcnt,char*data,int* datcnt) | ||||
{ | ||||
char iicdat=0; | ||||
dev->I2CONCLR = 0x28; | ||||
iicdat = (address<<1) & 0xFE; | ||||
int count = (*datcnt) + 2; | ||||
r10 | (*datcnt) = 0; | |||
r6 | while(dev->I2STAT != 0xF8); //waiting for device to be ready /!\ should add timeout | |||
dev->I2CONSET = (1<<5); //initiate transfert | ||||
while(count>0) | ||||
{ | ||||
while((dev->I2CONSET & 0x08)!=0x08); | ||||
switch(dev->I2STAT) | ||||
{ | ||||
case 0x08: | ||||
iicputdata(dev,iicdat,(1<<2),0x28); | ||||
iicdat = *cmd++; | ||||
break; | ||||
case 0x10: | ||||
iicputdata(dev,iicdat,(1<<2),0x28); | ||||
iicdat = *cmd++; | ||||
*cmdcnt = (*cmdcnt) - 1; | ||||
break; | ||||
case 0x18: | ||||
iicputdata(dev,iicdat,0,0x08); | ||||
if((*cmdcnt)>1) | ||||
{ | ||||
iicdat = *cmd++; | ||||
*cmdcnt = (*cmdcnt) - 1; | ||||
} | ||||
else | ||||
{ | ||||
count--; | ||||
iicdat = *data++; | ||||
} | ||||
break; | ||||
case 0x28: | ||||
iicputdata(dev,iicdat,(1<<2),0x08); | ||||
if((*cmdcnt)>1) | ||||
{ | ||||
iicdat = *cmd++; | ||||
*cmdcnt = (*cmdcnt) - 1; | ||||
} | ||||
else | ||||
{ | ||||
count--; | ||||
*datcnt = (*datcnt)+1; | ||||
iicdat = *data++; | ||||
} | ||||
break; | ||||
case 0x20: | ||||
r10 | return i2noack; | |||
r6 | count = 0; | |||
break; | ||||
case 0x30: | ||||
r10 | return i2noack; | |||
r6 | count = 0; | |||
break; | ||||
case 0x38: | ||||
r10 | return i2arbloss; | |||
r6 | count = 0; | |||
break; | ||||
default: | ||||
break; | ||||
} | ||||
} | ||||
dev->I2CONSET = (1<<4) + (1<<2); | ||||
dev->I2CONCLR = 1<<3; | ||||
return i2noerr; | ||||
} | ||||
i2ctrl i2cwrite(i2cDev* dev,char address,char*data,int* cnt) | ||||
{ | ||||
char iicdat=0; | ||||
dev->I2CONCLR = 0x28; | ||||
iicdat = (address<<1) & 0xFE; | ||||
int count = (*cnt) + 1; | ||||
*cnt = 0; | ||||
while(dev->I2STAT != 0xF8); //waiting for device to be ready /!\ should add timeout | ||||
dev->I2CONSET = (1<<5); //initiate transfert | ||||
while(count>0) | ||||
{ | ||||
while((dev->I2CONSET & 0x08)!=0x08); | ||||
switch(dev->I2STAT) | ||||
{ | ||||
case 0x08: | ||||
iicputdata(dev,iicdat,(1<<2),0x28); | ||||
iicdat = *data++; | ||||
break; | ||||
case 0x10: | ||||
iicputdata(dev,iicdat,(1<<2),0x28); | ||||
iicdat = *data++; | ||||
break; | ||||
case 0x18: | ||||
iicputdata(dev,iicdat,0,0x08); | ||||
count--; | ||||
iicdat = *data++; | ||||
break; | ||||
case 0x28: | ||||
iicputdata(dev,iicdat,(1<<2),0x08); | ||||
*cnt = (*cnt)+1; | ||||
count--; | ||||
iicdat = *data++; | ||||
break; | ||||
case 0x20: | ||||
return i2noack; | ||||
count = 0; | ||||
break; | ||||
case 0x30: | ||||
return i2noack; | ||||
count = 0; | ||||
break; | ||||
case 0x38: | ||||
return i2arbloss; | ||||
count = 0; | ||||
break; | ||||
default: | ||||
break; | ||||
} | ||||
} | ||||
dev->I2CONSET = (1<<4) + (1<<2); | ||||
dev->I2CONCLR = 1<<3; | ||||
return i2noerr; | ||||
} | ||||
i2ctrl i2cread(i2cDev* dev,char address,char*data,int* cnt) | ||||
{ | ||||
char iicdat=0; | ||||
dev->I2CONCLR = 0x28; | ||||
iicdat = (address<<1) + 1; | ||||
r10 | unsigned int count = (*cnt); | |||
r6 | *cnt = 0; | |||
while(dev->I2STAT != 0xF8); //waiting for device to be ready /!\ should add timeout | ||||
dev->I2CONSET = (1<<5); //initiate transfert | ||||
r10 | while(count!=0) | |||
r6 | { | |||
while((dev->I2CONSET & 0x08)!=0x08); | ||||
switch(dev->I2STAT) | ||||
{ | ||||
r10 | while((dev->I2CONSET & (1<<3))!=(1<<3)); | |||
r6 | case 0x08: | |||
iicputdata(dev,iicdat,(1<<2),0x28); | ||||
break; | ||||
case 0x10: | ||||
iicputdata(dev,iicdat,(1<<2),0x28); | ||||
break; | ||||
case 0x40: | ||||
r10 | if((count!=1)) dev->I2CONSET = (1<<2); | |||
else dev->I2CONCLR = (1<<2); | ||||
dev->I2CONCLR = 1<<3; | ||||
r6 | break; | |||
case 0x50: | ||||
r10 | if((count==2)) iicgetdata(dev,iicdat,(0),(0x0c)) | |||
else iicgetdata(dev,iicdat,(4),(8)) | ||||
r6 | count--; | |||
*cnt = (*cnt) + 1; | ||||
r10 | *data = iicdat; | |||
data++; | ||||
r6 | break; | |||
case 0x48: | ||||
r10 | dev->I2CONSET = 0x14; | |||
dev->I2CONCLR = 8; | ||||
return i2noerr; | ||||
r6 | break; | |||
case 0x58: | ||||
r10 | iicgetdata(dev,iicdat,(0x14),(8)); | |||
count--; | ||||
*cnt = (*cnt) + 1; | ||||
*data = iicdat; | ||||
data++; | ||||
return i2noerr; | ||||
r6 | break; | |||
default: | ||||
break; | ||||
} | ||||
} | ||||
r10 | dev->I2CONSET = (1<<4); dev->I2CONCLR =(1<<2); | |||
r6 | dev->I2CONCLR = 1<<3; | |||
return i2noerr; | ||||
} | ||||
void i2csetup(i2cDev* dev,int clkH,int clkL) | ||||
{ | ||||
dev->I2CONCLR = 0x6C; | ||||
dev->I2SCLH = clkH; | ||||
dev->I2SCLL = clkL; | ||||
dev->I2CONSET = 1<<6; //enable I2C block | ||||
dev->I2CONCLR = 0x28; | ||||
} | ||||
void i2cenable(i2cDev* dev) | ||||
{ | ||||
dev->I2CONSET = 1<<6; | ||||
} | ||||
void i2cdisable(i2cDev* dev) | ||||
{ | ||||
dev->I2CONCLR = (1<<6); | ||||
} | ||||
i2cDev* i2copen(int count){ | ||||
i2cDev* dev; | ||||
switch(count) | ||||
{ | ||||
case 0: | ||||
dev = (i2cDev*)((unsigned long)LPC_I2C0_BASE); | ||||
break; | ||||
case 1: | ||||
dev = (i2cDev*)((unsigned long)LPC_I2C1_BASE); | ||||
break; | ||||
case 2: | ||||
dev = (i2cDev*)((unsigned long)LPC_I2C2_BASE); | ||||
break; | ||||
default: | ||||
dev = (i2cDev*)0; | ||||
break; | ||||
} | ||||
return dev; | ||||
} | ||||
unsigned char i2cgetpclkfactor(i2cDev* dev) | ||||
{ | ||||
unsigned int clksel=0; | ||||
const char clkselDec[]={4,1,2,8}; | ||||
switch((int)dev) | ||||
{ | ||||
case (int)LPC_I2C0_BASE: | ||||
clksel = (LPC_SC->PCLKSEL0>>14) & 3; | ||||
break; | ||||
case (int)LPC_I2C1_BASE: | ||||
clksel = (LPC_SC->PCLKSEL1>>6) & 3; | ||||
break; | ||||
case (int)LPC_I2C2_BASE: | ||||
clksel = (LPC_SC->PCLKSEL1>>20) & 3; | ||||
break; | ||||
default: | ||||
break; | ||||
} | ||||
return clkselDec[clksel]; | ||||
} | ||||
void i2csetpclkfactor(i2cDev* dev,unsigned char pclkfactor) | ||||
{ | ||||
const char clkselDec[]={1,1,2,2,0,0,0,0,3}; | ||||
unsigned int clksel=0; | ||||
switch((int)dev) | ||||
{ | ||||
case (int)LPC_I2C0_BASE: | ||||
LPC_SC->PCLKSEL0 |= clkselDec[pclkfactor]<<14; | ||||
LPC_SC->PCLKSEL0 &= clkselDec[pclkfactor]<<14; | ||||
break; | ||||
case (int)LPC_I2C1_BASE: | ||||
LPC_SC->PCLKSEL1 |= clkselDec[pclkfactor]<<6; | ||||
LPC_SC->PCLKSEL1 &= clkselDec[pclkfactor]<<6; | ||||
break; | ||||
case (int)LPC_I2C2_BASE: | ||||
LPC_SC->PCLKSEL1 |= clkselDec[pclkfactor]<<20; | ||||
LPC_SC->PCLKSEL1 &= clkselDec[pclkfactor]<<20; | ||||
break; | ||||
default: | ||||
break; | ||||
} | ||||
} | ||||
void i2csetdatarate(i2cDev* dev,unsigned int dataRate) | ||||
{ | ||||
unsigned int pclk = 0; | ||||
unsigned int cpuclk=0; | ||||
unsigned int i2csclkl=0; | ||||
if(dev==0)return; | ||||
cpuclk = coregetCpuFreq(); | ||||
pclk = cpuclk / i2cgetpclkfactor(dev); | ||||
i2csclkl = (pclk / dataRate)>>1; | ||||
if(i2csclkl<4) i2csclkl = 4; | ||||
i2csetup(dev,i2csclkl,i2csclkl); | ||||
} | ||||
r10 | int i2cgetdatarate(i2cDev* dev) | |||
{ | ||||
unsigned int dataRate=0; | ||||
unsigned int pclk = 0; | ||||
unsigned int cpuclk=0; | ||||
unsigned int i2csclkl=0; | ||||
if(dev==0)return; | ||||
cpuclk = coregetCpuFreq(); | ||||
pclk = cpuclk / i2cgetpclkfactor(dev); | ||||
dataRate = pclk /( dev->I2SCLH + dev->I2SCLL); | ||||
return dataRate; | ||||
} | ||||
r6 | ||||
r10 | ||||