/*! \file i2c.c
\author Travis Goodspeed
-
- GoodFET I2C Master Application
- Handles basic I/O
-
+ \brief I2C Master
*/
#include "platform.h"
#include "command.h"
+#include "i2c.h"
-#include <signal.h>
-#include <io.h>
-#include <iomacros.h>
-
+#ifndef _GNU_ASSEMBLER_
+#include <msp430.h>
+#endif
//Pins and I/O
#include <jtag.h>
-#define SDA TDI
-#define SCL TDO
+
+//! Handles an i2c command.
+void i2c_handle_fn( uint8_t const app,
+ uint8_t const verb,
+ uint32_t const len);
+
+// define the i2c app's app_t
+app_t const i2c_app = {
+
+ /* app number */
+ I2C_APP,
+
+ /* handle fn */
+ i2c_handle_fn,
+
+ /* name */
+ "I2C",
+
+ /* desc */
+ "\tThe I2C app implements the i2c bus protocol thus\n"
+ "\tturning your GoodFET into a USB-to-i2c adapter.\n"
+};
#define I2CDELAY(x) delay(x<<4)
//2xx only, need 1xx compat code
-#define CLRSDA P5OUT&=~SDA
-#define SETSDA P5OUT|=SDA
-#define CLRSCL P5OUT&=~SCL
-#define SETSCL P5OUT|=SCL
+#define SDA TDI
+#define SCL TDO
-#define READSDA (P5IN&SDA?1:0)
-#define SETBOTH P5OUT|=(SDA|SCL)
+#define SDAINPUT SPIDIR&=~SDA
+#define SDAOUTPUT SPIDIR|=SDA
+#define SCLINPUT SPIDIR&=~SCL
+#define SCLOUTPUT SPIDIR|=SCL
+
+#define PULLON SPIREN|=(SDA|SCL)
+#define PULLOFF SPIREN&=~(SDA|SCL)
+
+#define CLRSDA SPIOUT&=~SDA
+#define SETSDA SPIOUT|=SDA
+#define CLRSCL SPIOUT&=~SCL
+#define SETSCL SPIOUT|=SCL
+
+#define READSDA (SPIIN&SDA?1:0)
+#define SETBOTH SPIOUT|=(SDA|SCL)
#define I2C_DATA_HI() SETSDA
#define I2C_DATA_LO() CLRSDA
//#warning "Using internal resistors. Won't work on 161x devices."
-//! Inits bitbanging port, must be called before using the functions below
-void I2C_Init()
+// Take control of the bus
+void I2C_Take()
{
-
- //Clear SDA and SCL.
- //Direction, not value, is used to set the value.
- //(Pull-up or 0.)
-
- P5DIR|=(SDA|SCL);
- P5REN|=SDA|SCL;
-
-
I2C_CLOCK_HI();
I2C_DATA_HI();
+ SCLOUTPUT;
+ SDAOUTPUT;
+}
+
+void I2C_Release()
+{
+ SDAINPUT;
+ SCLINPUT;
+}
+//! Inits bitbanging port, must be called before using the functions below
+void I2C_Init()
+{
+ I2C_Take();
+ //PULLON;
I2CDELAY(1);
}
+// XXX This is never called...
+void I2C_Exit()
+{
+ I2C_Release();
+ PULLOFF;
+}
+
//! Write an I2C bit.
void I2C_WriteBit( unsigned char c )
{
I2C_CLOCK_LO();
I2CDELAY(1);
-
- if(c>0)
- I2C_DATA_LO();
-
- I2CDELAY(1);
}
//! Read an I2C bit.
unsigned char I2C_ReadBit()
{
- I2C_DATA_HI();
-
+ SDAINPUT;
I2C_CLOCK_HI();
- I2CDELAY(1);
unsigned char c = READSDA;
+ if(c)
+ I2C_DATA_HI();
+ else
+ I2C_DATA_LO();
+ SDAOUTPUT;
+ I2CDELAY(1);
I2C_CLOCK_LO();
I2CDELAY(1);
return c;
}
+unsigned char I2C_ReadBit_Wait()
+{
+ SDAINPUT;
+ I2C_CLOCK_HI();
+
+ unsigned int i = 0;
+ unsigned char c = READSDA;
+
+ while(c>0 && i<=35)
+ {
+ I2CDELAY(1);
+ c = READSDA;
+ i++;
+ }
+
+ if(c)
+ I2C_DATA_HI();
+ else
+ I2C_DATA_LO();
+
+ SDAOUTPUT;
+ I2CDELAY(1);
+ I2C_CLOCK_LO();
+ I2CDELAY(1);
+
+ return c?0:1; // return true on ACK (0)
+}
//! Send a START Condition
void I2C_Start()
{
- // set both to high at the same time
- SETBOTH;
- I2CDELAY(1);
+ I2C_Take(); // XXX Should probably check to see if someone else is using the bus before we do this
+ I2CDELAY(3);
I2C_DATA_LO();
- I2CDELAY(1);
+ I2CDELAY(3);
I2C_CLOCK_LO();
I2CDELAY(1);
//! Send a STOP Condition
void I2C_Stop()
{
+ I2C_DATA_LO();
+ I2CDELAY(3);
+
I2C_CLOCK_HI();
- I2CDELAY(1);
+ I2CDELAY(3);
I2C_DATA_HI();
I2CDELAY(1);
+ I2C_Release();
}
//! write a byte to the I2C slave device
c<<=1;
}
- return I2C_ReadBit();
+ return I2C_ReadBit_Wait();
}
return res;
}
-
-//! Handles a monitor command.
-void i2chandle(unsigned char app,
- unsigned char verb,
- unsigned char len){
- unsigned char i;
- switch(verb){
-
- case PEEK:
- break;
- case POKE:
- break;
-
- case READ:
- if(len>0) //optional parameter of length
- len=cmddata[0];
- if(!len) //default value of 1
- len=1;
- for(i=0;i<len;i++)
- cmddata[i]=I2C_Read(1); //Always acknowledge
- txdata(app,verb,len);
- break;
- case WRITE:
- cmddata[0]=0;
- for(i=0;i<len;i++)
- cmddata[0]+=I2C_Write(cmddata[i]);
- txdata(app,verb,1);
- break;
- case START:
- I2C_Start();
- txdata(app,verb,0);
- break;
- case STOP:
- I2C_Stop();
- txdata(app,verb,0);
- break;
- case SETUP:
- I2C_Init();
- txdata(app,verb,0);
- break;
- }
+//! Handles an i2c command.
+void i2c_handle_fn( uint8_t const app,
+ uint8_t const verb,
+ uint32_t const len)
+{
+ unsigned char i;
+ unsigned long l;
+ switch(verb)
+ {
+ case READ:
+ l = len;
+ if(l > 0) //optional parameter of length
+ l=cmddata[0];
+ if(!l) //default value of 1
+ l=1;
+ I2C_Start();
+ for(i=0; i < l; i++)
+ cmddata[i]=I2C_Read(i<l?1:0);
+ I2C_Stop();
+ txdata(app,verb,l);
+ break;
+ case WRITE:
+ I2C_Start();
+ cmddata[0] = cmddata[0] << 1;
+ for(i=0; i<len; i++) {
+ if (!I2C_Write(cmddata[i])) //if NACK
+ break;
+ }
+ I2C_Stop();
+ cmddata[0] = i;
+ txdata(app,verb,1);
+ break;
+ case PEEK:
+ l = cmddata[0];
+ I2C_Start();
+ unsigned char address = cmddata[1] << 1;
+ I2C_Write(address);
+ for(i=2; i < len; i++){
+ I2C_Write(cmddata[i]);
+ }
+ I2C_Start();
+ I2C_Write(address|1); // spit out the target address again and flip the read bit
+ I2CDELAY(1); // XXX We should wait for clock to go high here XXX
+ for(i=0; i < l; i++)
+ cmddata[i]=I2C_Read(i+1<l?1:0); // If the next i is still less than l, then ACK
+ I2C_Stop();
+ txdata(app,verb,l);
+ break;
+ case POKE:
+ break;
+
+ case START:
+ I2C_Start();
+ txdata(app,verb,0);
+ break;
+ case STOP:
+ I2C_Stop();
+ txdata(app,verb,0);
+ break;
+ case SETUP:
+ I2C_Init();
+ txdata(app,verb,0);
+ break;
+ }
}