Subversion Repositories Projects

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/****************************************************************************
 *   Copyright (C) 2009-2010 by Claas Anders "CaScAdE" Rathje               *
 *   admiralcascade@gmail.com                                               *
 *   Project-URL: http://www.mylifesucks.de/oss/c-strom/                    *
 *                                                                          *
 *   This program is free software; you can redistribute it and/or modify   *
 *   it under the terms of the GNU General Public License as published by   *
 *   the Free Software Foundation; either version 2 of the License.         *
 *                                                                          *
 *   This program is distributed in the hope that it will be useful,        *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 *   GNU General Public License for more details.                           *
 *                                                                          *
 *   You should have received a copy of the GNU General Public License      *
 *   along with this program; if not, write to the                          *
 *   Free Software Foundation, Inc.,                                        *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.              *
 ****************************************************************************/



/****************************************************************************
 *                                                                          *
 *  Most of the i²c/twi code is originally from                             *
 *  http://www.rn-wissen.de/index.php/TWI_Slave_mit_avr-gcc                 *
 *                                                                          *
 ****************************************************************************/


#include <avr/interrupt.h>
#include <util/twi.h>
#include "i2c_slave.h"
#include "spi_union.h"

void init_twi_slave(uint8_t address) {
    TWAR = address;
    TWCR &= ~(1 << TWSTA) | (1 << TWSTO);
    TWCR |= (1 << TWEA) | (1 << TWEN) | (1 << TWIE);
    i2c_buf_adr = 0xFF;
    //sei();
}

ISR(TWI_vect) {
    uint8_t data = 0;
        //PORTD ^=  (1 << PD7); // toggle LED for test
    switch (TW_STATUS) {
        case TW_SR_SLA_ACK: // 0x60 Slave Receiver, wurde adressiert   
            TWCR_ACK; // next byte received
            i2c_buf_adr = 0xFF; // buf_adr undef
            break;
        case TW_SR_DATA_ACK: // 0x80 Slave Receiver,Daten empfangen
            data = TWDR; //Empfangene Daten auslesen
            if (i2c_buf_adr == 0xFF) {//erster Zugriff, Bufferposition setzen                  
                if (data <= I2C_BUFFER_SIZE) { //Kontrolle ob gewünschte Adresse im erlaubten bereich
                    i2c_buf_adr = data; //Bufferposition wie adressiert setzen
                } else {
                    i2c_buf_adr = 0; //Adresse auf Null setzen. Ist das sinnvoll?
                }
                TWCR_ACK; // nächstes Datenbyte empfangen, ACK danach, um nächstes Byte anzufordern
            } else {//weiterer Zugriff, Daten empfangen            
                i2c_rx_buffer[i2c_buf_adr] = data; //Daten in Buffer schreiben
                i2c_buf_adr++; //Buffer-Adresse weiterzählen für nächsten Schreibzugriff
                if (i2c_buf_adr < (I2C_BUFFER_SIZE - 1)) {//im Buffer ist noch Platz für mehr als ein Byte
                    TWCR_ACK; // nächstes Datenbyte empfangen, ACK danach, um nächstes Byte anzufordern
                } else {//es kann nur noch ein Byte kommen, dann ist der Buffer voll
                    TWCR_NACK; //letztes Byte lesen, dann NACK, um vollen Buffer zu signaliseren
                }
            }
            break;
        case TW_ST_SLA_ACK: //?!?
        case TW_ST_DATA_ACK: //0xB8 Slave Transmitter, weitere Daten wurden angefordert
            if (i2c_buf_adr == 0xFF) {//zuvor keine Leseadresse angegeben!            
                i2c_buf_adr = 0;
            }
            TWDR = i2c_tx_buffer[i2c_buf_adr]; //Datenbyte senden
            i2c_buf_adr++; //bufferadresse für nächstes Byte weiterzählen
            if (i2c_buf_adr < (I2C_BUFFER_SIZE - 1)) {//im Buffer ist mehr als ein Byte, das gesendet werden kann
                TWCR_ACK; //nächstes Byte senden, danach ACK erwarten
            } else {
                TWCR_NACK; //letztes Byte senden, danach NACK erwarten
            }
            break;
        case TW_ST_DATA_NACK: //0xC0 Keine Daten mehr gefordert
        case TW_SR_DATA_NACK: //0x88
        case TW_ST_LAST_DATA: //0xC8  Last data byte in TWDR has been transmitted (TWEA = “0”); ACK has been received
        case TW_SR_STOP: // 0xA0 STOP empfangen
        default:
            TWCR_RESET; //Übertragung beenden, warten bis zur nächsten Adressierung
            break;
    }
}