iic.c
350 lines
| 11.3 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" | ||||
r12 | #define iicputdata(iicdev,W,IICONSET,IICONCLR) {((_i2cDev)(iicdev))->I2DAT = (W);\ | |||
((_i2cDev)(iicdev))->I2CONSET = (IICONSET);\ | ||||
((_i2cDev)(iicdev))->I2CONCLR = (IICONCLR);} | ||||
r6 | ||||
r12 | #define iicgetdata(iicdev,W,IICONSET,IICONCLR) {(W) = ((_i2cDev)(iicdev))->I2DAT;\ | |||
((_i2cDev)(iicdev))->I2CONSET = (IICONSET);\ | ||||
((_i2cDev)(iicdev))->I2CONCLR = (IICONCLR);} | ||||
r6 | ||||
r12 | i2ctrl i2cwrite2(i2cDev dev,char address,char*cmd,int* cmdcnt,char*data,int* datcnt) | |||
r6 | { | |||
char iicdat=0; | ||||
r12 | ((_i2cDev)dev)->I2CONCLR = 0x28; | |||
r6 | iicdat = (address<<1) & 0xFE; | |||
int count = (*datcnt) + 2; | ||||
r10 | (*datcnt) = 0; | |||
r12 | while(((_i2cDev)dev)->I2STAT != 0xF8); //waiting for device to be ready /!\ should add timeout | |||
((_i2cDev)dev)->I2CONSET = (1<<5); //initiate transfert | ||||
r6 | while(count>0) | |||
{ | ||||
r12 | while((((_i2cDev)dev)->I2CONSET & 0x08)!=0x08); | |||
switch(((_i2cDev)dev)->I2STAT) | ||||
r6 | { | |||
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; | ||||
} | ||||
} | ||||
r12 | ((_i2cDev)dev)->I2CONSET = (1<<4) + (1<<2); | |||
((_i2cDev)dev)->I2CONCLR = 1<<3; | ||||
r6 | return i2noerr; | |||
} | ||||
r12 | i2ctrl i2cwrite(i2cDev dev,char address,char*data,int* cnt) | |||
r6 | { | |||
char iicdat=0; | ||||
r12 | ((_i2cDev)dev)->I2CONCLR = 0x28; | |||
r6 | iicdat = (address<<1) & 0xFE; | |||
int count = (*cnt) + 1; | ||||
*cnt = 0; | ||||
r12 | while(((_i2cDev)dev)->I2STAT != 0xF8); //waiting for device to be ready /!\ should add timeout | |||
((_i2cDev)dev)->I2CONSET = (1<<5); //initiate transfert | ||||
r6 | while(count>0) | |||
{ | ||||
r12 | while((((_i2cDev)dev)->I2CONSET & 0x08)!=0x08); | |||
switch(((_i2cDev)dev)->I2STAT) | ||||
r6 | { | |||
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; | ||||
} | ||||
} | ||||
r12 | ((_i2cDev)dev)->I2CONSET = (1<<4) + (1<<2); | |||
((_i2cDev)dev)->I2CONCLR = 1<<3; | ||||
r6 | return i2noerr; | |||
} | ||||
r12 | i2ctrl i2cread(i2cDev dev,char address,char*data,int* cnt) | |||
r6 | { | |||
char iicdat=0; | ||||
r12 | ((_i2cDev)dev)->I2CONCLR = 0x28; | |||
r6 | iicdat = (address<<1) + 1; | |||
r10 | unsigned int count = (*cnt); | |||
r6 | *cnt = 0; | |||
r12 | while(((_i2cDev)dev)->I2STAT != 0xF8); //waiting for device to be ready /!\ should add timeout | |||
((_i2cDev)dev)->I2CONSET = (1<<5); //initiate transfert | ||||
r10 | while(count!=0) | |||
r6 | { | |||
r12 | while((((_i2cDev)dev)->I2CONSET & 0x08)!=0x08); | |||
switch(((_i2cDev)dev)->I2STAT) | ||||
r6 | { | |||
r12 | while((((_i2cDev)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: | ||||
r12 | if((count!=1)) ((_i2cDev)dev)->I2CONSET = (1<<2); | |||
else ((_i2cDev)dev)->I2CONCLR = (1<<2); | ||||
((_i2cDev)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: | ||||
r12 | ((_i2cDev)dev)->I2CONSET = 0x14; | |||
((_i2cDev)dev)->I2CONCLR = 8; | ||||
r10 | 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; | ||||
} | ||||
} | ||||
r12 | ((_i2cDev)dev)->I2CONSET = (1<<4); | |||
((_i2cDev)dev)->I2CONCLR =(1<<2); | ||||
((_i2cDev)dev)->I2CONCLR = 1<<3; | ||||
r6 | return i2noerr; | |||
} | ||||
r12 | void i2csetup(i2cDev dev,int clkH,int clkL) | |||
r6 | { | |||
r12 | ((_i2cDev)dev)->I2CONCLR = 0x6C; | |||
((_i2cDev)dev)->I2SCLH = clkH; | ||||
((_i2cDev)dev)->I2SCLL = clkL; | ||||
((_i2cDev)dev)->I2CONSET = 1<<6; //enable I2C block | ||||
((_i2cDev)dev)->I2CONCLR = 0x28; | ||||
r6 | } | |||
r12 | void i2cenable(i2cDev dev) | |||
r6 | { | |||
r12 | ((_i2cDev)dev)->I2CONSET = 1<<6; | |||
r6 | } | |||
r12 | void i2cdisable(i2cDev dev) | |||
r6 | { | |||
r12 | ((_i2cDev)dev)->I2CONCLR = (1<<6); | |||
r6 | } | |||
r12 | i2cDev i2copen(int count){ | |||
i2cDev dev; | ||||
r6 | switch(count) | |||
{ | ||||
case 0: | ||||
r12 | dev = (i2cDev)((unsigned long)LPC_I2C0_BASE); | |||
r6 | break; | |||
case 1: | ||||
r12 | dev = (i2cDev)((unsigned long)LPC_I2C1_BASE); | |||
r6 | break; | |||
case 2: | ||||
r12 | dev = (i2cDev)((unsigned long)LPC_I2C2_BASE); | |||
r6 | break; | |||
default: | ||||
r12 | dev = (i2cDev)0; | |||
r6 | break; | |||
} | ||||
return dev; | ||||
} | ||||
r12 | unsigned char i2cgetpclkfactor(i2cDev dev) | |||
r6 | { | |||
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]; | ||||
} | ||||
r12 | void i2csetpclkfactor(i2cDev dev,unsigned char pclkfactor) | |||
r6 | { | |||
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; | ||||
} | ||||
} | ||||
r12 | void i2csetdatarate(i2cDev dev,unsigned int dataRate) | |||
r6 | { | |||
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); | ||||
} | ||||
r12 | int i2cgetdatarate(i2cDev dev) | |||
r10 | { | |||
unsigned int dataRate=0; | ||||
unsigned int pclk = 0; | ||||
unsigned int cpuclk=0; | ||||
unsigned int i2csclkl=0; | ||||
r12 | if(dev==0)return 0; | |||
r10 | cpuclk = coregetCpuFreq(); | |||
pclk = cpuclk / i2cgetpclkfactor(dev); | ||||
r12 | dataRate = pclk /( ((_i2cDev)dev)->I2SCLH + ((_i2cDev)dev)->I2SCLL); | |||
r10 | return dataRate; | |||
} | ||||
r6 | ||||
r10 | ||||