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;
}
}