Hi!
I've modified the bit banging i2c code found on the Acme website to
work with port B.
I have gotten a strange behavior from ioctl that I cannot understand.
When my application starts up, it scans the i2c-bus to see what
devices are connected to it, and prints out a list of the connected
devices.
When the pull-up resistors for the bus are in place, everything works
perfectly, but if I remove them, my code hangs.
Since the inputs are floating without the pull-ups, I was expecting
the reads from the port pins to return random values, but the fact
that the code hangs makes no sense to me.
I also noticed the messages: "err: timer0 irq for gpio" and "err: PA
irq for gpio" in the boot log, but I don't know if my problem has
anything to do with it.
I really want to know what's going on, because this might cause me
serious trouble later on.
I'm attaching the i2c routines below.
Regards
/Tobias Reneskog
/**********************************************************/
#define I2C_DATA_LINE 1<<6 //on GPIOB
#define I2C_CLOCK_LINE 1<<0 //on GPIOB
int i2c_getbit(void);
void i2c_dir_out(void);
void i2c_dir_in(void);
void i2c_data(int state);
void i2c_clk(int state);
void ReadDataAck(unsigned char *ucdata);
void ReadDataNack(unsigned char *ucdata);
void Start(void);
void Stop(void);
int WriteData(unsigned char x);
void i2c_open(void);
void i2c_close(void);
/************************** I2C-bus 1
***************************************/
// Get the SDA line state
int i2c_getbit(void) {
unsigned int value;
value=ioctl(fd_gpiob, _IO(ETRAXGPIO_IOCTYPE, IO_READBITS));
if ((value&(I2C_DATA_LINE))==0) return 0;
else return 1;
}
// Set the SDA line as output
void i2c_dir_out(void){
int iomask;
iomask = I2C_DATA_LINE;
ioctl(fd_gpiob, _IO(ETRAXGPIO_IOCTYPE, IO_SETGET_OUTPUT), &iomask);
}
// Set the SDA line as input
void i2c_dir_in(void){
int iomask;
iomask = I2C_DATA_LINE;
ioctl(fd_gpiob, _IO(ETRAXGPIO_IOCTYPE, IO_SETGET_INPUT), &iomask);
}
// Set the SDA line state
void i2c_data(int state){
if (state==1) {
i2c_dir_in();
} else {
i2c_dir_out();
}
}
// Set the SCL line state
void i2c_clk(int state){
int iomask;
iomask = I2C_CLOCK_LINE;
if (state==1) ioctl(fd_gpiob, _IO(ETRAXGPIO_IOCTYPE,
IO_SETGET_INPUT), &iomask);
else ioctl(fd_gpiob, _IO(ETRAXGPIO_IOCTYPE, IO_SETGET_OUTPUT), &iomask);
}
/************************* I2C bus 1
***********************************/
// Open the GPIO dev
void i2c_open(void){
int iomask;
//I2C-1
iomask = I2C_CLOCK_LINE;
ioctl(fd_gpiob, _IO(ETRAXGPIO_IOCTYPE, IO_SETGET_INPUT), &iomask);
ioctl(fd_gpiob, _IO(ETRAXGPIO_IOCTYPE, IO_CLRBITS), I2C_CLOCK_LINE);
iomask = I2C_DATA_LINE;
ioctl(fd_gpiob, _IO(ETRAXGPIO_IOCTYPE, IO_SETGET_INPUT), &iomask);
ioctl(fd_gpiob, _IO(ETRAXGPIO_IOCTYPE, IO_CLRBITS), I2C_DATA_LINE);
}
// Close the GPIO dev
void i2c_close(void){
i2c_dir_in();
i2c_clk(1);
}
// Send a start sequence to I2C bus
void Start(void){
i2c_data(1);
i2c_clk(1);
i2c_data(0);
i2c_clk(0);//Added by TR:
}
// Send a stop sequence to I2C bus
void Stop(void){
i2c_clk(0);
i2c_data(0);
i2c_clk(1);
i2c_data(1);
}
void ReadDataAck(unsigned char *ucdata){
unsigned char value = 0;
int bitvalue;
int i;
// Read data byte
i2c_dir_in();
for (i=0;i<8;i++){
i2c_clk(1);
bitvalue = i2c_getbit();
value |= bitvalue;
if(i<7) value <<= 1;
i2c_clk(0);
}
// Send Ack
i2c_data(0);
i2c_clk(1);
i2c_clk(0);
i2c_dir_in();
*ucdata = value;
}
void ReadDataNack(unsigned char *ucdata){
unsigned char value = 0;
int bitvalue;
int i;
// Read data byte
i2c_dir_in();
for (i=0;i<8;i++) {
i2c_clk(1);
bitvalue = i2c_getbit();
value |= bitvalue;
if (i<7) value <<= 1;
i2c_clk(0);
}
i2c_clk(1);
i2c_clk(0);
*ucdata = value;
}
// Send a byte to the I2C bus and return the ack sequence from slave
// 0 = Nack, 1=Ack
int WriteData(unsigned char x){
int i;
int ack;
for (i=0;i<8;i++) {
if (x & 0x80) i2c_data(1);
else i2c_data(0);
i2c_clk(1);
i2c_clk(0);
x <<= 1;
}
i2c_dir_in();
i2c_clk(1);
ack=i2c_getbit();
i2c_clk(0);
if (ack==0) return 0;
else return 1;
}
/*******************************/
int scani2c(char verbose){
unsigned char cntr;
int nbr_devices=0;
char devicename[40];
if(verbose) flogf("\nScanning I2C-bus 1:\n");
for(cntr = 2; cntr < 252; cntr += 2){
Start();
if(!WriteData(cntr)){
if(verbose){
resolvei2c(cntr, devicename);
flogf("Found device @ 0x%X - ", cntr);
flogf("%s\n", devicename);
}
nbr_devices++;
}
Stop();
}
if(verbose){
flogf("_____________________________________\n");
flogf("Found %i devices\n\n", nbr_devices);
}
return nbr_devices;
}
int resolvei2c(int deviceid, char *devicename){
int deviceid2;
int cnt;
FILE *f_i2cbase;
f_i2cbase = fopen(file_i2cbase, "r");
do{
fscanf(f_i2cbase, "%x,%s", &deviceid2, devicename);
if(deviceid2 == deviceid) break;
}while(!feof(f_i2cbase));
fclose(f_i2cbase);
if(deviceid2 == deviceid){
for(cnt = 0; cnt < strlen(devicename); cnt++){
if(devicename[cnt] == '_') devicename[cnt] = ' ';
}
return 0;
}
else{
sprintf(devicename, "Unknown device");
return 1;
}
}