Hoi,

Ik heb een i2c driver geschreven die perfect werkt met verschillende device's zoals IOexpanders, eeproms, temperatuur sensoren etc.
Nu het probleem: Als ik een digitaal kompas (CMPS03) ook via de I2C uitlees dan gaat dit maar 1 van de 3x goed.
De eerste keer uitlezen gaat helemaal goed.
Bij de 2e keer reageert het kompas niet op de start conditie van de I2C en krijg ik een timeout.
Bij de 3e keer krijg ik geen ACK zodra ik het adres heb verstuurd. Na de 3e keer gaat het uitlezen wel weer goed.
Na de 2e en 3e keer word de I2C bus opnieuw geinitialiseerd (gebeurd zodra een error is gedetecteerd). Ook word er tussen het uitlezen 100ms gewacht.

Heeft iemand een idee waarom het kompas zo raar doet? En waar dit aan kan liggen?

Gebruikte microcontroller is een AVR ATMega8.

Grtn Zundapp

Ok bij deze de code:
(TWI = I2C bij AVR)

TWI.h


#ifndef _TWI_FUNCTIONS
#define _TWI_FUNCTIONS

#include "main.h"           

/* Define */
#define TWI_PORTS     0x30      // Bit positions of SCL and SDA
#define TWI_TIMEOUT   (CPU_SPEED / 1000) / 4

// Status code's
#define START_SEND              0x08  /* Start had been transmitted */
#define RSTART_SEND             0x10  /* Repeated start has been transmitted */
#define SLAW_ACK                0x18  /* SLA + W has been transmitted and ACK has been received */
#define SLAW_NACK               0x20  /* SLA + W has been transmitted and NO ACK has been received */
#define DATA_SEND_ACK           0x28  /* Data byte has been transmitted and ACK has been received */
#define DATA_SEND_NACK          0x30  /* Data byte has been transmitted and NO ACK has been received */
#define ARB_LOST                0x38  /* Arbitration lost in SLA+W, SLA+R or data bytes */
#define SLAR_ACK                0x40  /* SLA + R has been transmitted and ACK has been received */
#define SLAR_NACK               0x48  /* SLA + R has been transmitted and NO ACK has been received */
#define DATA_RECEIVED_ACK       0x50  /* Data byte has been received and ACK has been returned */
#define DATA_RECEIVED_NACK      0x58  /* Data byte has been reveived and NO ACK has been returned */
#define SLAW_ACK_RECEIVED       0x60  /* Own SLA + W has been received, ACK has been returned */
#define ARB_LOST_MASTER         0x68  /* Arbitration lost in SLA+R/W as Master */
#define GNRL_CALL_RECEIVED      0x70  /* General call recieved, ACK returned */
#define ARB_LOST_MASTER2        0x78  /* Aribtration loast in SLA+R/W as Master when General call has been received */
#define ADDRESS_FAULT1          0x80  /* Previously addressed with own SLA+W. Data has been received, ACK returned */
#define ADDRESS_FAULT2          0x88  /* Previously addressed with own SLA+W. Data has been received, NO ACK returned */
#define ADDRESS_FAULT3          0x90  /* Previously addressed with general call. Data has been received, ACK returned */ 
#define ADDRESS_FAULT4          0x98  /* Previously addressed with general call. Data has been received, NO ACK returned */ 
#define SLAVE_FAULT             0xA0  /* STOP or RSTART condition received while still addressed as Slave */
#define SLAR_ACK_RECEIVED       0xA8  /* Own SLA + R has been received, ACK has been returned */
#define ARB_LOST_MASTER3        0xB0  /* Arbitration lost in SLA+R/W as Master */
#define SLV_DATA_SEND_ACK       0xB8  /* Slave transmitter: Data byte from TWDR has been transmitted and ACK has been received */
#define SLV_DATA_SEND_NACK      0xC0  /* Slave transmitter: Data byte from TWDR has been transmitted and NO ACK has been received */
#define SLV_LAST_DATA           0xC8  /* Last data byte in TWDR has been transmitted, ACK has been received  */

#define NO_STATE                0xF8  /* No status information available */
#define BUS_ERROR               0x00  /* BUS error due to illegal start or stop condition */
#define BUS_TIMEOUT             0xFF

/* Functie declaraties */
void TWI_Start(void);
void TWI_Write(unsigned char);
unsigned char TWI_Read(void);
void TWI_Stop(void);
void TWI_Wait(void);
void TWI_Init(void);

/* Variabelen */
extern bool twi_error;
extern bool twi_busy;
extern unsigned char twi_error_code;

#endif

TWI.c


#include "TWI.h"

/* Externe variabelen */
bool twi_busy = false;
bool twi_error = false;
unsigned char twi_error_code = 0;

/**********************************/
/*           TWI_Start            */
/**********************************/
void TWI_Start(void)
{
  if (twi_busy == false)        
  {
    twi_error = false;        /* Reset error flag */
    twi_error_code = 0;
  }
  twi_busy = true;
  
  if (twi_error == false)
  {
    /* Verzend Start conditie */
    TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);       /* Send start */
    TWI_Wait();
    
    if (!((TWSR == START_SEND) || (TWSR == RSTART_SEND) ))     
    { 
      if (twi_error == false)         twi_error_code = TWSR;
      twi_error = true;
    }
  }
}


/**********************************/
/*           TWI_Write            */
/**********************************/
void TWI_Write(unsigned char data)
{
  if (twi_error == false)
  {
    TWDR = data;                                            /* Schrijf adres van apparaat + write naar verzend register */
    TWCR = (1 << TWINT) | (1 << TWEN);                      /* Clear TWINT bit en enable TWEN bit waardoor "TWDR" word verstuurd */
    TWI_Wait();
    
    if (!((TWSR == SLAW_ACK) || (TWSR == DATA_SEND_ACK) || (TWSR == SLAR_ACK) )) 
    { 
      if (twi_error == false)         twi_error_code = TWSR;
      twi_error = true;
    }
  }
}


/**********************************/
/*            TWI_Read            */
/**********************************/
unsigned char TWI_Read(void)
{
  if (twi_error == false)
  {  
    /* Geef signaal om data in te lezen */
    TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);       /* Clear TWINT bit en enable TWEN bit en TWEA bit waardoor "data" word ontvangen en WEL Ack word verstuurd */
    TWI_Wait();

    if (TWSR != DATA_RECEIVED_ACK)
    { 
      if (twi_error == false)         twi_error_code = TWSR;
      twi_error = true;
    }    
  }
  if (twi_error == false)       return(TWDR);              /* De ontvangen data word teruggegeven aan de aanroepende functie  */
  else                          return(0);

}


/**********************************/
/*            TWI_Stop            */
/**********************************/
void TWI_Stop(void)
{
  if (twi_error == false)
  {  
    /* Verzend Stop conditie */  
    TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);       /* Send stop */
    while (!(TWCR & (1 << TWSTO)));
  }
  
  twi_busy = false;
}


/**********************************/
/*            TWI_Wait            */
/**********************************/
void TWI_Wait(void)
{
  unsigned long timeout = 0;
  while ( (!(TWCR & (1 << TWINT))) && (timeout < TWI_TIMEOUT) )                        /* Wacht totdat de TWINT bitje is geset, Dit betekend dat het commando is uitgevoerd */
  {
    timeout++;
  }
  
  if (timeout >= TWI_TIMEOUT)
  {
    /* Timeout error */
    twi_error = true;
    twi_error_code = BUS_TIMEOUT;
  }
  
}

void TWI_Init(void)
{
  twi_busy = true;                       /* Geen ander apparaat mag van de TWI gebruik maken */
  
  /* Disable TWI */
  DDRC &= ~TWI_PORTS;                    /* Poort C0 en C1 is input */
  PORTC &= ~TWI_PORTS;                   /* Disable Pull-up */
  TWBR = 0x00;                          
  TWSR = 0x00;                          
  TWDR = 0x00;                        
  TWCR = 0x00;  

  Delay_MS(100);
  
  /* TWI init */
  PORTC |= TWI_PORTS;                    /* activeer Pull-up weerstand op C0 en C1 */
  TWBR = 15;                             /* TWI Bit rate register = 10 bij prescaler 1 (formule in datasheet blz 173) */
  TWSR = 0x00;                           /* TWI Status register:  Prescaler = 1; */
  TWDR = 0x00;                           /* TWI Data register */
  TWCR = 0x00;                           /* TWI Control register , reset op 0x00 zodat twi niet vastloopt na sleepmode */
  TWAR = 0x00;                           /* TWI (Slave) Adres register = Het indentificatie nummer van de atmega32 */ 


  twi_busy = false;                      /* TWI mag door een ander apparaat gebruikt worden */
  twi_error = false;                     /* Reset error flag */
  twi_error_code = 0;
}

Kompas.c


#include "Kompas.h"
#include "TWI.h"

/**********************************/
/*        Kompas_Read        */
/**********************************/
unsigned int Kompas_Read()
{
  unsigned char data[2] = {0};
  int Value = 0;
  unsigned char adres = 0xC0;

  TWI_Start();                                    /* Zend start */
  TWI_Write(adres);                               /* Verzend SlaveAdres + Write */

  TWI_Write(0x02);                              /* Selecteer graden register */
       
  TWI_Start();                                  /* Verzend Start conditie (Repeated Start) */
  TWI_Write(adres + 1);                         /* Verzend SlaveAdres + Read */

  /* Als het apparaat reageerd */
  data[0] = TWI_Read();                       /* Lees 1e waarde in */
  data[1] = TWI_Read();                       /* Lees 2e waarde in */
    
  TWI_Stop();                                   /* Zend stop */

  if (twi_error == true)      
  {
    Handle_Error(twi_error_code);    
    TWI_Init();
  }
  else
  {
    Value = data[0] << 8;
    Value += data[1];
  }

  return(Value);

} /* Temp_Sensor_Read */

main.c


/**********************************/
/*              MAIN              */
/**********************************/
void main(void)
{
  int bearing = 0;
  char array[20] = {0};

  Init();  
  Uart_Init();  
  TWI_Init();

  /* main loop */
  while(1)
  {
    LED_ON;

    bearing = Kompas_Read();
    if (bearing != 0)
    {
      sprintf(array, "Bearing: %d  ", bearing);  
      Uart_Send_String(array, sizeof(array));
    }
    LED_OFF;
    Delay_MS(100);
    
  }

} /* MAIN */