/*************************************************************************** * Copyright (C) 01/2009 by Olaf Rempel * * razzor@kopf-tisch.de * * * * 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; 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. * ***************************************************************************/ #include #include #include "alix-usv.h" #include "usi-i2c-slave.h" #define USI_MASK 0x0F #define USI_MASK_ACKBIT 0x10 /* one (ack)bit / 8bits */ #define USI_MASK_OUTPUT 0x20 /* SDA is output / input */ #define USI_RESET 0x00 /* wait for Start Condition */ #define USI_START 0x01 /* Start detected */ #define USI_SLA 0x02 /* wait for Slave Address */ #define USI_SLAW_ACK 0x03 /* ACK Slave Address + Write (Master writes) */ #define USI_SLAR_ACK 0x04 /* ACK Slave Address + Read (Master reads) */ #define USI_DATW 0x05 /* receive Data */ #define USI_DATW_ACK 0x06 /* transmit ACK for received Data */ #define USI_DATR 0x07 /* transmit Data */ #define USI_DATR_ACK 0x08 /* receive ACK for transmitted Data */ static uint8_t usi_state; void usi_statemachine(void) { static uint8_t bcnt; uint8_t tmp = USIDR; uint8_t state = usi_state & USI_MASK; /* Start Condition detected */ if (state == USI_START) { usi_state = USI_SLA; /* Slave Address received => prepare ACK/NACK */ } else if (state == USI_SLA) { bcnt = 0; if (tmp == (I2C_ADDRESS | 0x00)) usi_state = USI_SLAW_ACK | USI_MASK_ACKBIT | USI_MASK_OUTPUT; else if (tmp == (I2C_ADDRESS | 0x01)) usi_state = USI_SLAR_ACK | USI_MASK_ACKBIT | USI_MASK_OUTPUT; else usi_state = USI_RESET; /* ACK after SLA+W / Data received => prepare data receive */ } else if (state == USI_SLAW_ACK || state == USI_DATW_ACK) { usi_state = USI_DATW; /* Data received => prepare ACK transmit */ } else if (state == USI_DATW) { usi_write(tmp, bcnt++); usi_state = USI_DATW_ACK | USI_MASK_ACKBIT | USI_MASK_OUTPUT; /* ACK after SLA+R transmitted / ACK after Data received => prepare data transmit */ } else if (state == USI_SLAR_ACK || (state == USI_DATR_ACK && tmp == 0x00)) { USIDR = usi_read(bcnt++); usi_state = USI_DATR | USI_MASK_OUTPUT; /* Data transmitted => prepare ACK receive */ } else if (state == USI_DATR) { usi_state = USI_DATR_ACK | USI_MASK_ACKBIT; /* NACK after Data received / default => go idle */ } else { usi_state = USI_RESET; } state = usi_state & USI_MASK; if (state == USI_RESET) { /* input */ DDRA &= ~I2C_SDA; /* Enable StartCondition Interrupt, TWI Mode, count both edges */ USICR = (1<