/*
 * UsiTwiSlave.c
 *
 * Created: 07.07.2012
 *  Author: Ulli
 */ 

/********************************************************************************************************
* Diese Datei ist eine Abwandlung der Atmel AppNote  "AVR312 - Using the USI module as a TWI slave"
*********************************************************************************************************/
#include <avr/io.h>
#include <avr/interrupt.h>
#include "GeneralDefinitions.h"
#include "UsiTwiSlave.h"

#define ASM_REG(x) asm("r" stringify(x)) // Aus einem Zahlenwert einen Register ausdruck machen aus ASM_REG(3) wird asm("r" "3"). Das verbindet der Compiler zu asm("r3").

// ******************************************************************************************************************************************************
// *                                                                                                                                                    *
// *  Konfiguration und Konstanten auf Zulässigkeit prüfen                                                                                              *
// *                                                                                                                                                    *
// ******************************************************************************************************************************************************
// ======================================================================================================================================================
// =  Geräte-Adresse                                                                                                                                    =
// ======================================================================================================================================================
#if (!defined(TWI_FIXED_TWI_ADDRESS) || (!(TWI_FIXED_TWI_ADDRESS > 0 && TWI_FIXED_TWI_ADDRESS < 128) && TWI_FIXED_TWI_ADDRESS !=NONE))
  #error 'TWI_FIXED_TWI_ADDRESS' wurde nicht oder nicht korrekt festgelegt. Mögliche Werte sind 'NONE' oder 1..127.
#endif

#if (!defined(TWI_ACCEPT_BROADCAST_MSG) || (TWI_ACCEPT_BROADCAST_MSG != TRUE && TWI_ACCEPT_BROADCAST_MSG != FALSE))
  #error 'TWI_ACCEPT_BROADCAST_MSG' wurde nicht oder nicht korrekt festgelegt. Mögliche Werte sind 'TRUE' oder 'FALSE'.
#endif

#if (TWI_FIXED_TWI_ADDRESS == NONE) // In diesem Fall wird 'TWI_ADRESS_REGISTER' nicht benötigt
  #undef  TWI_ADRESS_REGISTER
  #define TWI_ADRESS_REGISTER NONE
#endif

#if (!defined(TWI_ADRESS_REGISTER) || (!(TWI_ADRESS_REGISTER > 1 && TWI_ADRESS_REGISTER < 18) && TWI_ADRESS_REGISTER != NONE))
  #error 'TWI_ADRESS_REGISTER' wurde nicht oder nicht korrekt festgelegt. Mögliche Werte sind 'NONE' oder 2..18.
#endif

// ======================================================================================================================================================
// =   Betriebsmodus                                                                                                                                    =
// ======================================================================================================================================================
#if (!defined(TWI_OPERATION_MODE) || (TWI_OPERATION_MODE != TWI_MODE_STANDARD && TWI_OPERATION_MODE != TWI_MODE_SIMPLE && TWI_OPERATION_MODE != TWI_MODE_REGISTER))
  #error 'TWI_OPERATION_MODE' wurde nicht oder nicht korrekt festgelegt. Mögliche Werte sind 'TWI_MODE_STANDARD', 'TWI_MODE_SIMPLE' oder 'TWI_MODE_REGISTER'.
#endif

#if (!defined(TWI_TRANSMISSION_START_MSG) || (TWI_TRANSMISSION_START_MSG != TRUE && TWI_TRANSMISSION_START_MSG != FALSE && TWI_TRANSMISSION_START_MSG != INLINE))
  #error 'TWI_TRANSMISSION_START_MSG' wurde nicht oder nicht korrekt festgelegt
#endif

// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - Betriebsmodus STANDARD                                                                                                                             -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
#if (TWI_OPERATION_MODE == TWI_MODE_STANDARD)
  #if (!defined(TWI_RECEIVE_MODE) || (TWI_RECEIVE_MODE != NONE && TWI_RECEIVE_MODE != TWI_CALLBACK && TWI_RECEIVE_MODE != TWI_CB_INLINE))
    #error 'TWI_RECEIVE_MODE' wurde nicht oder nicht korrekt festgelegt. Mögliche Werte sind 'NONE', 'TWI_CALLBACK' oder TWI_CB_INLINE.
  #endif
  
  #if (!defined(TWI_DATA_REQUEST_MODE) || (TWI_DATA_REQUEST_MODE != STANDARD && TWI_RECEIVE_MODE != INLINE))
    #error 'TWI_DATA_REQUEST_MODE' wurde nicht oder nicht korrekt festgelegt. Mögliche Werte sind 'STANDARD' oder 'INLINE'.
  #endif
#endif // TWI_OPERATION_MODE == TWI_MODE_STANDARD

// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - Betriebsmodus SIMPLE                                                                                                                               -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
#if (TWI_OPERATION_MODE == TWI_MODE_SIMPLE)  // TWI_CB_INLINE wird in UsiSlave.h umgewandelt
  #if (!defined(TWI_RECEIVE_MODE) || (TWI_RECEIVE_MODE != NONE && TWI_RECEIVE_MODE != TWI_AUTO && TWI_RECEIVE_MODE != TWI_FLAG && TWI_RECEIVE_MODE != TWI_CALLBACK))
    #error 'TWI_RECEIVE_MODE' wurde nicht oder nicht korrekt festgelegt. Mögliche Werte sind 'NONE', 'TWI_AUTO', 'TWI_FLAG', 'TWI_CALLBACK' oder TWI_CB_INLINE.
  #endif
#endif // TWI_OPERATION_MODE == TWI_MODE_SIMPLE

// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - Betriebsmodus REGISTER                                                                                                                             -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
#if (TWI_OPERATION_MODE == TWI_MODE_REGISTER)  // TWI_CB_INLINE wird in UsiSlave.h umgewandelt
  #if (!defined(TWI_RECEIVE_MODE) || (TWI_RECEIVE_MODE != NONE && TWI_RECEIVE_MODE != TWI_AUTO && TWI_RECEIVE_MODE != TWI_FLAG && TWI_RECEIVE_MODE != TWI_CALLBACK ))
    #error 'TWI_RECEIVE_MODE' wurde nicht oder nicht korrekt festgelegt. Mögliche Werte sind 'NONE', 'TWI_AUTO', 'TWI_FLAG', 'TWI_CALLBACK' oder TWI_CB_INLINE.
  #endif

  #if ((TWI_RECEIVE_MODE == TWI_AUTO) || (TWI_RECEIVE_MODE == TWI_FLAG))
    #if (!defined(TWI_WRITE_PERMIT) || (TWI_WRITE_PERMIT < 0))
      #error 'TWI_WRITE_PERMIT' wurde nicht oder nicht korrekt festgelegt. Mögliche Werte sind  0..sizeof I2CRegister_t.
    #endif
  #endif // (TWI_RECEIVE == TWI_SIMPLE) || (TWI_RECEIVE == TWI_FLAG)

  #if (!defined(TWI_REGISTER_INDEX_REGISTER) || (!(TWI_REGISTER_INDEX_REGISTER > 1 && TWI_REGISTER_INDEX_REGISTER < 18) && TWI_REGISTER_INDEX_REGISTER != NONE))
    #error 'TWI_REGISTER_INDEX_REGISTER' wurde nicht oder nicht korrekt festgelegt. Mögliche Werte sind 'NONE' oder 2..18.
  #endif

  #if (!defined(TWI_STATE_REGISTER) || (!(TWI_STATE_REGISTER > 1 && TWI_STATE_REGISTER < 18) && TWI_STATE_REGISTER != NONE))
    #error 'TWI_REGISTER_INDEX_REGISTER' wurde nicht oder nicht korrekt festgelegt. Mögliche Werte sind 'NONE' oder 2..18.
  #endif

  #if (!defined(I2C_REGISTER_DEFAULT))
    #error 'I2C_REGISTER_DEFAULT' ist nicht definiert
  #endif
#endif // TWI_OPERATION_MODE == TWI_MODE_REGISTER

// ======================================================================================================================================================
// =   Modifizierungen                                                                                                                                  =
// ======================================================================================================================================================


#if (!defined(USI_INT_MESSAGE) || (USI_INT_MESSAGE != TRUE && USI_INT_MESSAGE != FALSE))
  #error 'USI_INT_MESSAGE' wurde nicht oder nicht korrekt festgelegt
#endif

#if (!defined(USI_OVF_TWI_STATE_REGISTER) || (!(USI_OVF_TWI_STATE_REGISTER > 1 && USI_OVF_TWI_STATE_REGISTER < 18) && USI_OVF_TWI_STATE_REGISTER !=NONE))
  #error 'USI_OVF_TWI_STATE_REGISTER' wurde nicht oder nicht korrekt festgelegt. Mögliche Werte sind 'NONE' oder 1..18.
#endif


// ******************************************************************************************************************************************************
// *                                                                                                                                                    *
// *  Variablen und Zugriffsfunktionen bereit stellen                                                                                                   *
// *                                                                                                                                                    *
// ******************************************************************************************************************************************************
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - TwiAddress bereit stellen                                                                                                                          -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
#if (TWI_FIXED_TWI_ADDRESS == NONE)
  #if (TWI_ADRESS_REGISTER != NONE) // Diese Variable muss nur in diesem Modul bekannt sein
    register uint8_t TwiDeviceAddress ASM_REG(TWI_ADRESS_REGISTER); // Geräte-Adresse
  #else
    static volatile uint8_t TwiDeviceAddress; // Status der Datenübertragung
#endif // TWI_ADRESS_REGISTER != NONE

void TwiSetAddress(uint8_t TwiAddress)
{ TwiDeviceAddress = TwiAddress << 1;}
#endif // TWI_FIXED_TWI_ADDRESS == NONE

// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - TwiData bereit stellen                                                                                                                             -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
#if (TWI_OPERATION_MODE == TWI_MODE_SIMPLE)
  volatile uint8_t TwiData;
#endif // TWI_RECEIVE_MODE == TWI_SIMPLE

// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - TwiDataReceivedFlag bereit stellen                                                                                                                 -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
#if (TWI_RECEIVE_MODE == TWI_FLAG) // Die Variable wird benötigt
  volatile uint8_t TwiDataReceivedFlag;
#endif // TWI_RECEIVE_MODE == TWI_FLAG

// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - I2C-Register bereit stellen                                                                                                                        -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
#if (TWI_OPERATION_MODE == TWI_MODE_REGISTER)
  volatile I2CRegister_t I2CRegister = {I2C_REGISTER_DEFAULT};
#endif // TWI_OPERATION_MODE == TWI_MODE_REGISTER

// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - TransmissionState bereit stellen                                                                                                                   -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
#if (TWI_OPERATION_MODE == TWI_MODE_REGISTER)
  typedef enum        // Steuerung der Datenübertragung
  { TS_WaitForIndex,  // Als nächste wird die Übertragung des Index erwartet
    TS_WriteData      // Als nächstes werden Daten übertragen
  } TransmissionState_t;

  #if (TWI_STATE_REGISTER != NONE) // Diese Variable muss nur in diesem Modul bekannt sein
      register TransmissionState_t TransmissionState ASM_REG(TWI_STATE_REGISTER); // Status der Datenübertragung
  #else
      static volatile TransmissionState_t TransmissionState; // Status der Datenübertragung
  #endif // TWI_STATE_REGISTER != NONE
#endif // TWI_OPERATION_MODE == TWI_MODE_REGISTER
  
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - RegisterIndex bereit stellen                                                                                                                       -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
#if (TWI_OPERATION_MODE == TWI_MODE_REGISTER)
  #if (TWI_REGISTER_INDEX_REGISTER != NONE) // Diese Variable muss nur in diesem Modul bekannt sein
    register uint8_t RegisterIndex ASM_REG(TWI_REGISTER_INDEX_REGISTER); // Zur Aufnahme des Register-Index
  #else
    static volatile uint8_t RegisterIndex;
  #endif // TWI_REGISTER_INDEX_REGISTER != NONE
#endif // TWI_OPERATION_MODE == TWI_MODE_REGISTER

// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - USI_TWI_Overflow_State bereit stellen                                                                                                              -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
typedef enum
{ UTO_CheckAaddress,
  UTO_SendData,
  UTO_RequestReplyFromSendData,
  UTO_CheckReplyFromSendData,
  UTO_RequestData,
  UTO_GetDataAndSendACK
} USI_TWI_Overflow_State_t;

#if (USI_OVF_TWI_STATE_REGISTER != NONE) // Diese Variable muss nur in diesem Modul bekannt sein
  register USI_TWI_Overflow_State_t USI_TWI_Overflow_State ASM_REG(USI_OVF_TWI_STATE_REGISTER); // Zur Aufnahme des Register-Index
#else
  static volatile USI_TWI_Overflow_State_t USI_TWI_Overflow_State;
#endif // TWI_REGISTER_INDEX_REGISTER != NONE


// ******************************************************************************************************************************************************
// *                                                                                                                                                    *
// *  CallBack-Funktionen (Event-Handler) entsprechend dem Betriebsmodus bereit stellen                                                                 *
// *                                                                                                                                                    *
// ******************************************************************************************************************************************************
// ======================================================================================================================================================
// =   CallBack-Funktionen bei Betriebsmodus STANDARD                                                                                                   =
// ======================================================================================================================================================
#if (TWI_OPERATION_MODE == TWI_MODE_STANDARD)
// Nichts zu tun, 'TwiDataRequest' und 'TwiDataReceived' werden in UsiTwiSlave.h deklariert und von der Applikation implementiert
#endif // TWI_OPERATION_MODE == TWI_MODE_STANDARD

// ======================================================================================================================================================
// =   CallBack-Funktionen bei Betriebsmodus SIMPLE                                                                                                     =
// ======================================================================================================================================================
#if (TWI_OPERATION_MODE == TWI_MODE_SIMPLE)
 static inline uint8_t TwiDataRequest (void) // interne Implemetierung von 'TwiDataRequest'
  { return TwiData;
  }

// - TwiDataReceived() entsprechend TWI_RECEIVE_MODE impementieren                                                                                      -
  #if (TWI_RECEIVE_MODE == NONE)
    static inline void TwiDataReceived (uint8_t data) {}  // nichts zu tun
  #endif // TWI_RECEIVE == NONE
  
  #if (TWI_RECEIVE_MODE == TWI_AUTO)
    static inline void TwiDataReceived (uint8_t data)
	{ TwiData = data;
	}
  #endif // TWI_RECEIVE == TWI_SIMPLE

  #if (TWI_RECEIVE_MODE == TWI_FLAG)
	static inline void TwiDataReceived (uint8_t data)
	{ TwiData = data;
	  TwiDataReceivedFlag = true;
	}
  #endif // TWI_RECEIVE == TWI_FLAG
#endif // TWI_OPERATION_MODE == TWI_MODE_SIMPLE

// ======================================================================================================================================================
// =   CallBack-Funktionen bei Betriebsmodus REGISTER                                                                                                   =
// ======================================================================================================================================================
#if (TWI_OPERATION_MODE == TWI_MODE_REGISTER)
  static inline uint8_t TwiDataRequest(void) // interne Implemetierung von 'TwiDataRequest'
  { uint8_t tmp = ((uint8_t *)&I2CRegister)[RegisterIndex]; // nächstes Byte aus dem Register lesen
    if (RegisterIndex < (sizeof I2CRegister)-1)
	    RegisterIndex ++;
	return tmp;
  }

  // interne Implementierung von 'TwiTransmissionStart' in Form von 'TwiTransmissionStartRegister'
  // Ereignis ggf. Appliktion weiterleiten
  static inline void TwiTransmissionStartRegister(TwiTransferType rw)
  { TransmissionState = TS_WaitForIndex; // Übertragungsstatus auf "Übertragungsbeginn" setzen
 	#if (TWI_TRANSMISSION_START_MSG)
 	  TwiTransmissionStart (rw);  // Beginn einer neuen Übertragung durchreichen
 	#endif
  }

// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - TwiDataReceived() entsprechend TWI_RECEIVE_MODE impementieren                                                                                      -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
  #if (TWI_RECEIVE_MODE == NONE)
    static inline void TwiDataReceived(uint8_t index, uint8_t data)
    { }
  #endif // TWI_RECEIVE_MODE == NONE
  
  #if (TWI_RECEIVE_MODE == TWI_AUTO)
    static inline void TwiDataReceived(uint8_t index, uint8_t data)
	#if (TWI_WRITE_PERMIT > 0)
      { if (RegisterIndex >= TWI_WRITE_PERMIT)            // Nur erlaubte Bereiche beschreiben
	      ((uint8_t *)&I2CRegister)[RegisterIndex] = data;
      }
    #else
	  { ((uint8_t *)&I2CRegister)[RegisterIndex] = data;
	  }
	#endif // TWI_WRITE_PERMIT > 0
  #endif // TWI_RECEIVE_MODE == TWI_AUTO

  #if (TWI_RECEIVE_MODE == TWI_FLAG)
    static inline void TwiDataReceived(uint8_t index, uint8_t data)
	#if (TWI_WRITE_PERMIT > 0)
	  { if (RegisterIndex >= TWI_WRITE_PERMIT)            // Nur erlaubte Bereiche beschreiben
		  ((uint8_t *)&I2CRegister)[RegisterIndex] = data;
	    TwiDataReceivedFlag = true;
	  }
	#else
	  { ((uint8_t *)&I2CRegister)[RegisterIndex] = data;
	    TwiDataReceivedFlag = true;
	  }
	#endif // TWI_WRITE_PERMIT > 0
  #endif // TWI_RECEIVE_MODE == TWI_FLAG

  // Liefert Daten aus dem I2C-Modul.
  // Diese Funktion wird aufgerufen, wenn das I2C-Modul Daten erhalten hat.
  // Transfer vom Master zum Slave
  static inline void TwiDataReceivedRegister(uint8_t data)
  { // Wenn mit einer neuen Übertragung begonnen wird, wird zuerst die Registeradresse übertragen
    // danach Datenbytes
    switch (TransmissionState)
    { case TS_WaitForIndex:  // neue Register Adresse entgegen nehmen
	       if (data < sizeof(I2CRegister)) // nicht außerhalb des Registers ...
	         RegisterIndex = data;
		   else
		     RegisterIndex = sizeof(I2CRegister); // ... ansonsten ans Ende.
		   TransmissionState = TS_WriteData;
		   break;
	  case TS_WriteData:  // Datenbyte empfangen
		   TwiDataReceived(RegisterIndex, data);
		   if (RegisterIndex < (sizeof I2CRegister)-1)
		     RegisterIndex ++;
		   break;
    } // switch (TransmissionState)
  }
#endif // TWI_OPERATION_MODE == TWI_MODE_REGISTER


// ******************************************************************************************************************************************************
// *                                                                                                                                                    *
// *  USI                                                                                                                                               *
// *                                                                                                                                                    *
// ******************************************************************************************************************************************************
// ======================================================================================================================================================
// =   Controllerabhängige Definitionen                                                                                                                 =
// ======================================================================================================================================================
#if defined (__AVR_ATtiny25__) || defined (__AVR_ATtiny45__) || defined (__AVR_ATtiny85__)
#define PORT_USI          PORTB
#define USI_SDA_IO        PB0
#define USI_SCL_IO        PB2
#elif defined (__AVR_ATtiny24__) || defined (__AVR_ATtiny44__) || defined (__AVR_ATtiny84__)
#define PORT_USI          PORTA
#define USI_SDA_IO        PA6
#define USI_SCL_IO        PA4
#elif defined (__AVR_ATtiny2313__) || defined (__AVR_ATtiny4313__)
#define PORT_USI          PORTB
#define USI_SDA_IO        PB5
#define USI_SCL_IO        PB7
#define USI_OVF_vect      USI_OVERFLOW_vect
#else
   #error I2CPins: Für diesen Prozesortyp liegen keine Angaben vor
#endif

#define DDR_USI      DDR(PORT_USI)
#define PIN_USI      PIN(PORT_USI)
#define USI_PIN_MASK ((1<<USI_SCL_IO) | (1<<USI_SDA_IO))

// ======================================================================================================================================================
// =   Macros zur USI-TWI-Steuerung                                                                                                                     =
// ======================================================================================================================================================
// Alle Flags löschen und Overflow-Counter zurücksetzen 
#define CLEAR_ALLFLAGS ((1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0<<USICNT0))

inline void SET_USI_TO_SEND_ACK(void)
{ USIDR    =  0;                                              /* ACK bereitstellen.                                   */ 
  DDR_USI |=  (1<<USI_SDA_IO);                                /* SDA in Output-Modus.                                 */ 
  USISR    =  (0<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|  /* Alle Flags außer Start-Condition zurücksetzen.       */ 
              (0x0E<<USICNT0);                                /* USI-Counter für Ausgabe von 1 Bit vorbereiten.       */ 
}

inline void SET_USI_TO_READ_ACK(void)
{ DDR_USI &=  ~(1<<USI_SDA_IO);                               /* SDA in Input-Modus                                   */ 
  USIDR    =  0;                                              /* USIDR löschen.                                       */ 
  USISR    =  (0<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|  /* Alle Flags außer Start-Condition zurücksetzen.       */ 
              (0x0E<<USICNT0);                                /* USI-Counter für das Einlesen von 1 Bit vorbereiten.  */ 
}

inline void SET_USI_TO_SEND_DATA(void)
{ DDR_USI |=  (1<<USI_SDA_IO);                                /* SDA in Output-Modus.                                 */ 
  USISR    =  (0<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|  /* Alle Flags außer Start-Condition zurücksetzen.       */ 
              (0x0<<USICNT0);                                 /* USI-Counter für Ausgabe von 8 Bits vorbereiten.      */ 
}

inline void SET_USI_TO_READ_DATA(void)
{ DDR_USI &= ~(1<<USI_SDA_IO);                                /* SDA in Input-Modus                                   */ 
  USISR    =  (0<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|  /* Alle Flags außer Start-Condition zurücksetzen.       */ 
              (0x0<<USICNT0);                                 /* USI-Counter für das Einlesen von 8 Bits vorbereiten. */ 
}

inline void SET_USI_TO_TWI_START_CONDITION_MODE(void)
{ USICR    =  (1<<USISIE)|                                    /* Start-Condition-Interrupt freigeben.                 */ 
              (0<<USIOIE)|                                    /* Counter-Overflow-Interrupt abschalten.               */ 
              (1<<USIWM1)|(1<<USIWM0)|                        /* USI in den Two-Wire-Modus versetzen.                 */ 
              (1<<USICS1)|(0<<USICS0)|(0<<USICLK);            /* Clock Source des Shift Register: External            */ 
                                                              /* Datenübernahme bei positiver Flanke                  */ 
  USISR    =  (0<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|  /* Alle Flags außer Start-Condition zurücksetzen.       */ 
              (0x0<<USICNT0);                                 /* USI-Counter zurücksetzen                             */ 
}

// ======================================================================================================================================================
// =   Initialisierungsfunktion TwiInitialize()                                                                                                         =
// ======================================================================================================================================================
// TwiInitialize() gibt es in zwei Varianten, je nach dem ob mit festen oder änderbaren Geräteadressen gearbeitet wird.
#if (TWI_FIXED_TWI_ADDRESS != NONE)
  void TwiInitialize(void)
  {
#else
  void TwiInitialize(uint8_t TwiAddress)
  { TwiDeviceAddress = TwiAddress << 1;        // Geräte-Adresse speichern
#endif

  PORT_USI |=  (1<<USI_SCL_IO)|(1<<USI_SDA_IO);      // SCL und SDA auf high setzen.
  DDR_USI  |=  (1<<USI_SCL_IO);                      // SCL in Output-Modus versetzen.
  DDR_USI  &= ~(1<<USI_SDA_IO);                      // SDA in Input-Modus versetzen.
  USICR    =   (1<<USISIE)|                          // Start-Condition-Interrupt freigeben.
               (0<<USIOIE)|                          // Counter-Overflow-Interrupt sperren.
               (1<<USIWM1)|(1<<USIWM0)|              // USI in den Two-Wire-Modus versetzen.
               (1<<USICS1)|(0<<USICS0)|(0<<USICLK);  // Clock Source des Shift Register: External
                                                     // Datenübernahme bei positiver Flanke
  USISR    =   CLEAR_ALLFLAGS;                       // Alle Flags löschen und Overflow-Counter zurücksetzen.
}

// ======================================================================================================================================================
// =   ISR                                                                                                                                              =
// ======================================================================================================================================================
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - USI Start                                                                                                                                          -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// Initialisiert das USI für den Empfang des TWI-Address-Pakets.
ISR(USI_START_vect)
{ uint8_t tmpSignalState;

#if (USI_INT_MESSAGE == TRUE)
  InteruptOccured = true;
#endif

  USI_TWI_Overflow_State = UTO_CheckAaddress;  // Vorgabe für den nächsten Aufruf der Counter-Overflow Service-Routine setzen
  DDR_USI &= ~(1<<USI_SDA_IO);                       // SDA in Input-Modus versetzen
 
  // Warten bis SCL auf low geht, um sicher zu sein, dass die Startphase beendet ist.
  // Auch wenn eine Stop-Bedingung erkannt wurde, muss die Schleife wieder verlassen werden
  while ( (tmpSignalState = (PIN_USI & USI_PIN_MASK)) == (1<<USI_SCL_IO)); // solange SDA low und SCL high ist (Startbedingung)
  if (tmpSignalState == USI_PIN_MASK)  // SCL und SCA High: unerwartete Stopp-Bedingung erkannt
    SET_USI_TO_TWI_START_CONDITION_MODE();
  else
  { USICR = (1<<USISIE)|                         // Start-Condition-Interrupt zur RESTART-Erkennung eingeschaltet freigeben.
            (1<<USIOIE)|                         // Counter-Overflow-Interrupt freigeben
            (1<<USIWM1)|(1<<USIWM0)|             // USI in den Two-Wire-Modus versetzen. SCL nach Overflow-Erkennung halten.
            (1<<USICS1)|(0<<USICS0)|(0<<USICLK); // Clock Source des Shift Register: External
                                                 // Datenübernahme bei positiver Flanke
    USISR = CLEAR_ALLFLAGS;                      // Interrupt-Flags löschen. Löschen des Start-Condition-Flags gibt SCL frei.
  }
} 

// ------------------------------------------------------------------------------------------------------------------------------------------------------
// - USI Overflow                                                                                                                                       -
// ------------------------------------------------------------------------------------------------------------------------------------------------------
// Regelt die gesamte Kommunikation.
// Ist nur dann deaktiviert, wenn auf das Eintreten einer Startbedingung gewartet wird
ISR(USI_OVF_vect)
{ 
#if (USI_INT_MESSAGE == TRUE)
  InteruptOccured = true;
#endif
	
  switch (USI_TWI_Overflow_State)
  { // ---------- Address mode ----------
    // Adresse prüfen. Falls passend: ACK senden. Ansonsten USI zurücksetzen	
    case UTO_CheckAaddress:
      { uint8_t tmpUSIDR = USIDR;
        if ( //Adresse prüfen
             #if (TWI_FIXED_TWI_ADDRESS == NONE) 
		         ((uint8_t)(tmpUSIDR & 0xFE) == TwiDeviceAddress) 
			 #else
		         ((uint8_t)(tmpUSIDR & 0xFE) == (uint8_t)(TWI_FIXED_TWI_ADDRESS << 1))
			 #endif
			 #if (TWI_ACCEPT_BROADCAST_MSG)
		         || ((tmpUSIDR & 0xFE) == 0) 
			#endif
		   )  //Adresse prüfen
        { if (tmpUSIDR & 0x01)
		     USI_TWI_Overflow_State = UTO_SendData;
          else
		     USI_TWI_Overflow_State = UTO_RequestData;

          SET_USI_TO_SEND_ACK();
		  uint8_t rw = tmpUSIDR & 0x01;
		  #if (TWI_ACCEPT_BROADCAST_MSG)
		    if ((tmpUSIDR & 0xFE) == 0) // Broadcast
			  rw += 2;
		  #endif
		  #if  (TWI_OPERATION_MODE == TWI_MODE_REGISTER)
			TwiTransmissionStartRegister(rw);
	      #elif (TWI_TRANSMISSION_START_MSG)
            TwiTransmissionStart (rw);  // Beginn einer neuen Übertragung signalisieren
		  #endif 
        }
        else
        { SET_USI_TO_TWI_START_CONDITION_MODE();
        }
      }
      break;

	// ----- Master liest Daten ein ------
    // Antwort prüfen. Falls ACK gehe zu USI_SLAVE_SEND_DATA, Ansonsten USI zurücksetzen.
    case UTO_CheckReplyFromSendData:
      if ( USIDR ) // Falls NACK, benötigt der Master keine weiteren Daten.
      { SET_USI_TO_TWI_START_CONDITION_MODE();
        break;
      } 

    //Wenn der Master ACK sendet, von hier aus direkt zu USI_SLAVE_SEND_DATA durchreichen.

    // USIDR mit Daten füllen und USI für das Senden eines Bytes einrichten. Dann zu USI_SLAVE_REQUEST_REPLY_FROM_SEND_DATA
    case UTO_SendData:
      USIDR = TwiDataRequest(); // Daten abfordern
      USI_TWI_Overflow_State = UTO_RequestReplyFromSendData;
      SET_USI_TO_SEND_DATA();
      break;

    // USI zum Einlesen der Antwort des Masters einrichten. Dann USI_SLAVE_CHECK_REPLY_FROM_SEND_DATA
    case UTO_RequestReplyFromSendData:
      USI_TWI_Overflow_State = UTO_CheckReplyFromSendData;
      SET_USI_TO_READ_ACK();
	  break;

    // ----- Master schreibt Daten, Slave liest Daten ein -----
	// USI zum Einlesen von Daten konfigurieren. Nächster Zustand: USI_SLAVE_GET_DATA_AND_SEND_ACK
    case UTO_RequestData:
      USI_TWI_Overflow_State = UTO_GetDataAndSendACK; 
      SET_USI_TO_READ_DATA();
      break;

	// Daten aus USIDR auslesen und ACK senden. Nächster Zustand: USI_SLAVE_REQUEST_DATA
    case UTO_GetDataAndSendACK:
#if (TWI_OPERATION_MODE == TWI_MODE_REGISTER)
      TwiDataReceivedRegister(USIDR); // Daten verarbeiten
#else	  
  	  TwiDataReceived(USIDR); // Daten verarbeiten
#endif
      USI_TWI_Overflow_State = UTO_RequestData;
      SET_USI_TO_SEND_ACK();
      break;
  }
}
