TWI-Master Routinen kann ich hier gerne posten. Bei den Slave wirds dann aber etwas schwieriger. Es kommt auf deine Anwendung an, wie der Code empfangen/zwischengespeichert/gesendet wird. Außerdem kommt es darauf an, ob der Master nur senden, oder auch empfangen können soll.

Wenn du deine Anwendung beschreibst, könnt ich dir sicherlich bei der Erstellung eines Protokolls helfen, was geeignet ist.

Hier schonmal der TWI-Master code
Code:
Header-Datei:
#include <avr/io.h>

#define READ 1
#define WRITE 0
#define TWI_READY (TWCR & (1<<TWINT))

void TWIInit(void);
void TWIStart(uint8_t addr, uint8_t RW);
void TWIStop(void);
//Byte senden
uint8_t TWIWrite(uint8_t data );
//Byte empfangen
uint8_t TWIReadAck(void);
//letztes zu empfangendes Byte empfangen
uint8_t TWIReadNack(void);


.c Datei:
void TWIInit(void){
  PORTC |= 0x03;  //PULLUP Widerstaende (für ATmega32 geeignet)
  TWBR = 0xFF;
}

void TWIStart(uint8_t addr, uint8_t RW){
  uint8_t temp = 1;

  while(temp == 1){
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);   //START
    while(!TWI_READY);
    if(TWSR == 0x00) {TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);}
    if(TWSR != 0x08 && TWSR != 0x10) {continue;}

    TWDR = addr + RW;//LCD_BOARD_ADR;     //send ADR+W
    TWCR = (1<<TWINT) | (1<<TWEN);
    while(!TWI_READY);
    if(TWSR == 0x00) {TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);}
    if(TWSR != 0x18 && TWSR != 0x40) {continue;}
    temp = 0;
  }
}

void TWIStop(void){
  TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
  while(TWCR & (1<<TWSTO));
}

//Byte senden
uint8_t TWIWrite(uint8_t data ){
    TWDR = data;
    TWCR = (1<<TWINT) | (1<<TWEN);

    while(!TWI_READY);

    if(TWSR != 0x28){return 1;}
    return 0;
}

//Byte empfangen
uint8_t TWIReadAck(void){
    TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
    while(!TWI_READY);
    return TWDR;
}

//letztes zu empfangendes Byte empfangen
uint8_t TWIReadNack(void){
    TWCR = (1<<TWINT) | (1<<TWEN);
    while(!TWI_READY);
    return TWDR;
}
Auf einem ATmega32 hab ich den Code noch nicht getestet, allerdings sollte das keine Probleme machen.
Zuerst muss eine Start-Anweisung ausgeführt werden, die dem Slave sagt, was zutun ist. READ: Master liest, WRITE: Master schreibt.
Wenn Master schreibt, dann musst du die TWIWrite Funktion verwenden, um ein Byte zu senden. Wenn er liest, dann musst du die TWIReadAck Funktion verwenden, um Bytes zu lesen (außer das letzte Byte), für das letzte Byte verwendest du die TWIReadNack Funktion.
Am Ende kommt eine stop-Anweisung.

Wenn du einfach nur etwas an den Slave senden möchtest und nichts zurück erwartest, würde ich dir aber eher den SPI-Bus empfehlen, er ist deutlich schneller und für diesen Zweck am einfachsten zu programmieren.

Gruß, Yaro