I am having a problem with interfacing my Attiny861 with the magnetic field sensor, the HMC5843. I have the right address, but the chip doesn’t drop SDA low when I try to read the ACK bit. A little more about my setup is that it is a single master and a single slave without pull-up resistors. I also am not using the USI features or registers, and manually changing the ports.
The relevant code looks something like this:
#define F_CPU 1000000UL // Sets up the default speed for delay.h
#define T2_TWI 5 // >4,7us
#define T4_TWI 4 // >4,0us
void i2c_setup(void)
{
int i;
unsigned char messageBuf1[MESSAGEBUF1_SIZE] = {0x3C, 0x0A};
unsigned char size = 2;
unsigned char temp, data;
USI_TWI_Master_Initialise();
USI_TWI_Master_Start(); //Send a start command
USI_TWI_Master_Transfer( messageBuf1[0], 8, 0); //1st is variable, then bit length, then R/!W
temp = USI_TWI_Master_Transfer( temp , 1, 1); //Read ACK
PORT_LED = (temp);
unsigned char USI_TWI_Master_Transfer( unsigned char a, int b, int c )
{
int i;
unsigned char tmp;
if(c == 0) //write
{
DDR_USI |= (1<<PIN_USI_SDA);
for(i=0;i<b;i++)
{
tmp = a; //Set the Write Data to tmp
PORT_USI &= ~(1<<PIN_USI_SDA); // Zero the Data Pin
PORT_USI |= (0x01&(tmp>>(b-i-1))); // Put a bit on the bus based on the loop number
_delay_us(T2_TWI);
PORT_USI |= (1<<PIN_USI_SCL); // Generate positive SCL edge.
while( !(PIN_USI & (1<<PIN_USI_SCL)) ); // Wait for SCL to go high.
_delay_us(T4_TWI);
PORT_USI &= ~(1<<PIN_USI_SCL); // Pull SCL LOW.
}
PORT_USI |= (1<<PORT_USI_SDA);
}
else //read
{
for(i=0;i<b;i++)
{
DDR_USI &= ~(1<<PIN_USI_SDA); //Set to intput
_delay_us(T2_TWI);
PORT_USI |= (1<<PIN_USI_SCL); // Generate positve SCL edge.
while( !(PIN_USI & (1<<PIN_USI_SCL)) ); // Wait for SCL to go high.
tmp = ((PIN_USI & (1<<PIN_USI_SDA))<<(b-i-1)); // Read a bit shifted up by total loop number - number of loops
_delay_us(T4_TWI);
PORT_USI &= ~(1<<PIN_USI_SCL); // Pull SCL LOW.
}
}
_delay_us(T2_TWI);
return tmp; // Return the data from the USIDR
}
unsigned char USI_TWI_Master_Start( void )
{
/* Release SCL to ensure that (repeated) Start can be performed */
PORT_USI |= (1<<PIN_USI_SCL); // Release SCL.
while( !(PIN_USI & (1<<PIN_USI_SCL)) ); // Verify that SCL becomes high.
_delay_us(T2_TWI);
/* Generate Start Condition */
PORT_USI &= ~(1<<PIN_USI_SDA); // Force SDA LOW.
_delay_us(T4_TWI);
PORT_USI &= ~(1<<PIN_USI_SCL); // Pull SCL LOW.
return (TRUE);
}
unsigned char USI_TWI_Master_Stop( void )
{
DDR_USI |= (1<<PIN_USI_SDA)|(1<PIN_USI_SCL);
PORT_USI &= ~(1<<PIN_USI_SDA); // Pull SDA low.
PORT_USI |= (1<<PIN_USI_SCL); // Release SCL.
while( !(PIN_USI & (1<<PIN_USI_SCL)) ); // Wait for SCL to go high.
_delay_us(T4_TWI);
PORT_USI |= (1<<PIN_USI_SDA); // Release SDA.
_delay_us(T2_TWI);
return (TRUE);
}