/*------------------------------------------------------------------------------ -- 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) {((_i2cDev)(iicdev))->I2DAT = (W);\ ((_i2cDev)(iicdev))->I2CONSET = (IICONSET);\ ((_i2cDev)(iicdev))->I2CONCLR = (IICONCLR);} #define iicgetdata(iicdev,W,IICONSET,IICONCLR) {(W) = ((_i2cDev)(iicdev))->I2DAT;\ ((_i2cDev)(iicdev))->I2CONSET = (IICONSET);\ ((_i2cDev)(iicdev))->I2CONCLR = (IICONCLR);} i2ctrl i2cwrite2(i2cDev dev,char address,char*cmd,int* cmdcnt,char*data,int* datcnt) { char iicdat=0; ((_i2cDev)dev)->I2CONCLR = 0x28; iicdat = (address<<1) & 0xFE; int count = (*datcnt) + 2; (*datcnt) = 0; while(((_i2cDev)dev)->I2STAT != 0xF8); //waiting for device to be ready /!\ should add timeout ((_i2cDev)dev)->I2CONSET = (1<<5); //initiate transfert while(count>0) { while((((_i2cDev)dev)->I2CONSET & 0x08)!=0x08); switch(((_i2cDev)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: return i2noack; count = 0; break; case 0x30: return i2noack; count = 0; break; case 0x38: return i2arbloss; count = 0; break; default: break; } } ((_i2cDev)dev)->I2CONSET = (1<<4) + (1<<2); ((_i2cDev)dev)->I2CONCLR = 1<<3; return i2noerr; } i2ctrl i2cwrite(i2cDev dev,char address,char*data,int* cnt) { char iicdat=0; ((_i2cDev)dev)->I2CONCLR = 0x28; iicdat = (address<<1) & 0xFE; int count = (*cnt) + 1; *cnt = 0; while(((_i2cDev)dev)->I2STAT != 0xF8); //waiting for device to be ready /!\ should add timeout ((_i2cDev)dev)->I2CONSET = (1<<5); //initiate transfert while(count>0) { while((((_i2cDev)dev)->I2CONSET & 0x08)!=0x08); switch(((_i2cDev)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; } } ((_i2cDev)dev)->I2CONSET = (1<<4) + (1<<2); ((_i2cDev)dev)->I2CONCLR = 1<<3; return i2noerr; } i2ctrl i2cread(i2cDev dev,char address,char*data,int* cnt) { char iicdat=0; ((_i2cDev)dev)->I2CONCLR = 0x28; iicdat = (address<<1) + 1; unsigned int count = (*cnt); *cnt = 0; while(((_i2cDev)dev)->I2STAT != 0xF8); //waiting for device to be ready /!\ should add timeout ((_i2cDev)dev)->I2CONSET = (1<<5); //initiate transfert while(count!=0) { while((((_i2cDev)dev)->I2CONSET & 0x08)!=0x08); switch(((_i2cDev)dev)->I2STAT) { while((((_i2cDev)dev)->I2CONSET & (1<<3))!=(1<<3)); case 0x08: iicputdata(dev,iicdat,(1<<2),0x28); break; case 0x10: iicputdata(dev,iicdat,(1<<2),0x28); break; case 0x40: if((count!=1)) ((_i2cDev)dev)->I2CONSET = (1<<2); else ((_i2cDev)dev)->I2CONCLR = (1<<2); ((_i2cDev)dev)->I2CONCLR = 1<<3; break; case 0x50: if((count==2)) iicgetdata(dev,iicdat,(0),(0x0c)) else iicgetdata(dev,iicdat,(4),(8)) count--; *cnt = (*cnt) + 1; *data = iicdat; data++; break; case 0x48: ((_i2cDev)dev)->I2CONSET = 0x14; ((_i2cDev)dev)->I2CONCLR = 8; return i2noerr; break; case 0x58: iicgetdata(dev,iicdat,(0x14),(8)); count--; *cnt = (*cnt) + 1; *data = iicdat; data++; return i2noerr; break; default: break; } } ((_i2cDev)dev)->I2CONSET = (1<<4); ((_i2cDev)dev)->I2CONCLR =(1<<2); ((_i2cDev)dev)->I2CONCLR = 1<<3; return i2noerr; } void i2csetup(i2cDev dev,int clkH,int clkL) { ((_i2cDev)dev)->I2CONCLR = 0x6C; ((_i2cDev)dev)->I2SCLH = clkH; ((_i2cDev)dev)->I2SCLL = clkL; ((_i2cDev)dev)->I2CONSET = 1<<6; //enable I2C block ((_i2cDev)dev)->I2CONCLR = 0x28; } void i2cenable(i2cDev dev) { ((_i2cDev)dev)->I2CONSET = 1<<6; } void i2cdisable(i2cDev dev) { ((_i2cDev)dev)->I2CONCLR = (1<<6); } i2cDev i2copen(int count){ i2cDev dev; switch(count) { case 0: dev = (i2cDev)((unsigned long)I2C0_BASE_ADDR); break; case 1: dev = (i2cDev)((unsigned long)I2C1_BASE_ADDR); break; case 2: dev = (i2cDev)((unsigned long)I2C2_BASE_ADDR); 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)I2C0_BASE_ADDR: clksel = (PCLKSEL0>>14) & 3; break; case (int)I2C1_BASE_ADDR: clksel = (PCLKSEL1>>6) & 3; break; case (int)I2C2_BASE_ADDR: clksel = (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)I2C0_BASE_ADDR: PCLKSEL0 |= clkselDec[pclkfactor]<<14; PCLKSEL0 &= clkselDec[pclkfactor]<<14; break; case (int)I2C1_BASE_ADDR: PCLKSEL1 |= clkselDec[pclkfactor]<<6; PCLKSEL1 &= clkselDec[pclkfactor]<<6; break; case (int)I2C2_BASE_ADDR: PCLKSEL1 |= clkselDec[pclkfactor]<<20; 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); } int i2cgetdatarate(i2cDev dev) { unsigned int dataRate=0; unsigned int pclk = 0; unsigned int cpuclk=0; unsigned int i2csclkl=0; if(dev==0)return 0; cpuclk = coregetCpuFreq(); pclk = cpuclk / i2cgetpclkfactor(dev); dataRate = pclk /( ((_i2cDev)dev)->I2SCLH + ((_i2cDev)dev)->I2SCLL); return dataRate; }