/*------------------------------------------------------------------------------ -- 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" #define iicputdata(iicdev,W,IICONSET,IICONCLR) (iicdev)->I2DAT = (W);\ (iicdev)->I2CONSET = (IICONSET);\ (iicdev)->I2CONCLR = (IICONCLR); #define iicgetdata(iicdev,W,IICONSET,IICONCLR) (W) = (iicdev)->I2DAT;\ (iicdev)->I2CONSET = (IICONSET);\ (iicdev)->I2CONCLR = (IICONCLR); 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; *datcnt = 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 = *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: count = 0; break; case 0x30: count = 0; break; case 0x38: 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; 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); break; case 0x10: iicputdata(dev,iicdat,(1<<2),0x28); break; case 0x40: dev->I2CONSET = (1<<2); dev->I2CONCLR = (1<<3); count--; break; case 0x50: iicgetdata(dev,iicdat,(1<<2),(1<<3)); count--; *cnt = (*cnt) + 1; *data++ = iicdat; break; case 0x48: return i2noack; break; case 0x58: count = 0; return i2noack; break; default: break; } } dev->I2CONSET = (1<<4) + (1<<2); 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); }